ULL-MII-SYTWS / building-async-await-template

https://ull-mii-sytws.github.io/practicas/building-async-await.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Async-Await ≈ Generators + Promises

Goal

Imagine we are given a piece of code like the one below that uses async functions, how can we rewrite it using only promises and generator functions?

function doTask1() {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(1), 100)
    })
}

function doTask2(arg) {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(arg+2), 100)
    })
}

function doTask3(arg) {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(arg+3), 100)
    })
}

async function init() {
    const res1 = await doTask1();
    console.log(res1);
    
    const res2 = await doTask2(res1);
    console.log(res2);

    const res3 = await doTask3(res2);
    console.log(res3);

    return res3;
}

init(); // 1\n3\n6

It performs three asynchronous tasks, one after the other where each task depends on the completion of the previous task. Finally, it returns the result of the last task.

How can we rewrite it using generators?

Remember Generators

Remember:

  • When a generator function is called, its body is not executed right away.
  • Instead it returns an iterator-object which adheres to the iterator protocol i.e. it has a next method.
  • The only way to execute the body of the generator is by calling the next method on its iterator-object.
  • Every time the next method is called, its body is executed until the next yield expression.
  • The value of this expression is returned from the iterator.
  • This next method also accepts an argument.
  • Calling it with an argument replaces the current yield expression with the argument and resumes the execution till the next yield expression.

First Idea: Generators can yield Promises

By now you would be wondering, how do the generator functions help our situation? We need to model an asynchronous flow where we have to wait for certain tasks to finish before proceeding ahead. How can we do that?

Well, the most important insight here is that the generator-functions can yield promises too.

  • A generator function can yield a promise (for example an async task), and
  • its iterator can be controlled to halt for this promise to resolve (or reject), and then
  • proceed with the resolved (or rejected) value.

Rewriting the Async Function as a Generator

This pattern of weaving a an iterator with yielded promises allows us to model our requirement like this:

function doTask1(arg) {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(arg), 100)
    })
}

function doTask2(arg) {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(arg+2), 100)
    })
}

function doTask3(arg) {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(arg+3), 100)
    })
}

function* init(arg) {
    const res1 = yield doTask1(arg);
    console.log(res1);
    
    const res2 = yield doTask2(res1);
    console.log(res2);

    const res3 = yield doTask3(res2);
    console.log(res3);

    return res3;
}

Notice how this generator function resembles our async function!

A Function Controlling the Execution of the Generator

But this is only half the story. Now we need a way to execute its body.

We need a function waiter that can control the iterator of this generator function to "wait for the fulfillment of the promise yielded on each iteration". It has to:

  1. Halt every time a promise is yielded and
  2. Proceeds once the promise resolves (or rejects).

It sounds complicated, but takes only a few lines to implement.

Write the waiter function

Write the waiter function:

function waiter(genFun, arg) {
   // ... your code here
}

const doIt = waiter(init, 3);
doIt();

So that, when we run it with the generator above, we obtain:

➜  learning-async-iteration-and-generators git:(main) ✗ node 07-async-await-equal-generators-plus-promises/example.js 
3
5
8

Heres is a solution

See

About

https://ull-mii-sytws.github.io/practicas/building-async-await.html


Languages

Language:JavaScript 88.8%Language:Shell 11.2%