We all know that async/await is the syntactic sugar of Generator functions, so let’s explore Generator functions in JavaScript first.

Generator is a one-piece solution provided by ES6. Generator is a state machine that contains multiple states. Here is a generator function:

function* myGenerator () {
    yield 'hello'
    yield 'world'
    return 'ending'
}

const fn = myGenerator()

console.log(fn.next())
console.log(fn.next())
console.log(fn.next())
Copy the code

His printout looked like this:

Calling the next method of the generator function returns a traverser object containing the value and state. You can see that a return statement is encountered when done is false.

When a generator function follows

function* sum() {
	yield 3 + 4
}
Copy the code

When the corresponding next statement is not executed, the calculation following yield will not be executed. This is known as lazy execution.

What is the relation between generator function and async function? After learning, I find that async/await is generator plus an automatic execution function. Because the Generator cannot be executed automatically, it must be executed manually through the next method. So we can simulate async/await effects by wrapping the generator around an auto-executing function and returning a promise. Here’s how:

const { resolve } = require("path");

/* Test the function, return a promise */
const getData = function(n, time) {
    return new Promise((resolve, reject) = > {
        setTimeout(() = >{ resolve(n) }, time); })}/* A generator function that executes itself via the autoTick function
function* myGenerator () {
    const n1 = yield getData(10.2000);
    console.log(n1)
    const n2 = yield getData(20.2000);
    console.log(n2)
    return 
}

/* Auto-execute a function that automatically executes the generator function it receives */
function autoTick(generatorFunc) {
    return function() {
        const gen = generatorFunc.apply(this.arguments) 
        return new Promise((resolve,reject) = > {
            let res
            function step (key, args) {
                try{
                    res = gen[key](args)
                } catch(e) {
                    reject(e)
                }    
            const  { value, done } = res
            if(done) {
                return resolve(value)
            } else {
                return Promise.resolve(value).then(value= > {
                    step('next', value)
                })
            }
        }
        step('next')
    }
        )
    }
}
autoTick(myGenerator)()


Copy the code

You can see that the print result is as follows, and each number is printed at an interval of 2000ms:

The myGenerator method is equivalent to the following:

function* myGenerator () {
    const n1 = yield getData(10.2000);
    console.log(n1)
    const n2 = yield getData(20.2000);
    console.log(n2)
    return} is equivalent to >>>>>async myGenerator() {
    const n1 = await getData(10.2000);
    console.log(n1)
    const n2 = await getData(20.2000);
    console.log(n2)
    return 
}
// The only difference between them is the way they are written and whether they can execute themselves
Copy the code

Through this exploration, I have deepened my understanding of generator functions, iterators, async/await, rather than just knowing how to use them.