To talk about async, let’s talk about Generator functions

Generator

Generator functions are an asynchronous programming solution provided by ES6

function* helloWorld() {
  yield 'hello'
  yield 'world'
  return 'ending'
}
let hw = helloWorld()
Copy the code

The execution result

console.log(hw.next()) // Print {value: "hello", done: false}
console.log(hw.next()) // Print {value: "world", done: false}
console.log(hw.next()) // print {value: "ending", done: true}
console.log(hw.next()) // Print {value: undefined, done: true}
Copy the code

Generator function that returns an traverser object representing an internal pointer to the Generator function. Each call to the next method of the traverser object returns an object with both value and done properties. The value property represents the value of the current internal state and is the value of the expression following the yield expression; The done attribute is a Boolean value indicating whether the traversal is complete.

yield

Generator functions that use yield expressions become a pure __ deferred function __.

function* helloWorld() {
    console.log('hello' + ' world')}let hw = helloWorld()

setTimeout(() = > {
    hw.next()
}, 1000)
// Prints Hello World after 1 second
Copy the code
next

The yield expression itself returns no value, or always returns undefined. The next method can take an argument that is treated as the return value of the previous yield expression

function* f(x) {
  var y = 2 * (yield (x + 1))
  var z = yield (y / 3)
  return (x + y + z)
}

let g = f(0);
// Print 0(note that the first time the next method is used, the passing argument is invalid)
console.log(g.next())
//x = 0, y = 120 (2*60)
console.log(g.next(60))
//x = 0, y = 120, z = 200
console.log(g.next(200))
Copy the code

The context state of a Generator function does not change from its paused state to its resumed state. With the parameters of the next method, there is a way to continue injecting values into the function body after the Generator function has started running. That is, the behavior of the Generator function can be adjusted by injecting different values from outside to inside at different stages of its operation.

Asynchronous execution

function* f() {
    const data = yield (new Promise((resolve, reject) = > {
        setTimeout(() = > {
            resolve('hello async')},1000)}))console.log('hello world')}let g = f()

const data = g.next()
data.value.then(data= > {
    return data
}).then(data= > {
    //data == hello async
    g.next() // Print hello world
})
Copy the code

The Generator functions represent asynchronous operations succinctly, but process management (i.e. when to perform phase one and when to perform phase two) is inconvenient.

Thunk function

The Thunk function can be used for automatic flow management of Generator functions, and the following run method is an automatic executor of Generator functions

function* f() {
    const f1 = yield (new Promise((resolve, reject) = > {
        setTimeout(() = > {
            resolve('hello async A')},1000)}))const f2 = yield (new Promise((resolve, reject) = > {
        setTimeout(() = > {
            resolve('hello async B')},1000)}))console.log(f1, f2)
}


function run(fn) {
    let gen = fn()
    function next(data) {
      let result = gen.next(data)
      if (result.done) return
      result.value.then(data= > {
          next(data)
      })
    }
    next()
  }
  
run(f)
// Hello async A hello async B
Copy the code

Co module

The CO module is used for automatic execution of Generator functions

const co = require('co')

function* f() {
    const f1 = yield (new Promise((resolve, reject) = > {
        setTimeout(() = > {
            resolve('hello async A')},1000)}))const f2 = yield (new Promise((resolve, reject) = > {
        setTimeout(() = > {
            resolve('hello async B')},1000)}))console.log(f1, f2)
}


co(f).then(data= > {
	console.log('Execution complete')})Copy the code

The CO module allows you to avoid writing an executor for a Generator function, which will automatically execute as soon as you pass in a CO function that returns a Promise object

Co module part source, which receives a Generator function as a parameter

function co(gen) {
    var ctx = this;
    var args = slice.call(arguments.1);
    return new Promise(function(resolve, reject) {
      if (typeof gen === 'function') gen = gen.apply(ctx, args);
      if(! gen ||typeofgen.next ! = ='function') return resolve(gen);
  
      onFulfilled();
  
      function onFulfilled(res) {
        var ret;
        try {
          ret = gen.next(res);
        } catch (e) {
          return reject(e);
        }
        next(ret);
        return null;
      }
  
      function onRejected(err) {
        var ret;
        try {
          ret = gen.throw(err);
        } catch (e) {
          return reject(e);
        }
        next(ret);
      }
  
      function next(ret) {
        Ret. value is an expression returned by Generator return. If not, undefined
        if (ret.done) return resolve(ret.value);
        var value = toPromise.call(ctx, ret.value);
        // Call ondepressing to perform the next next
        if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
        // Yield must be followed by function, Promise, generator, array, object data types
        return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
          + 'but the following object was passed: "' + String(ret.value) + '"')); }})}Copy the code

async await

function* f() {
    const f1 = yield (new Promise((resolve, reject) = > {
        setTimeout(() = > {
            resolve('hello async A')},1000)}))const f2 = yield (new Promise((resolve, reject) = > {
        setTimeout(() = > {
            resolve('hello async B')},1000)}))console.log(f1, f2)
}

async function g(){
    const f1 = await (new Promise((resolve, reject) = > {
        setTimeout(() = > {
            resolve('hello async A')},1000)}))const f2 = await (new Promise((resolve, reject) = > {
        setTimeout(() = > {
            resolve('hello async B')},1000)}))console.log(f1, f2)
}
Copy the code

An async function simply replaces the asterisk (*) of a Generator function with async, replaces yield with await, and that’s it

advantages

1. Built-in actuators Functions must rely on actuators, such as the CO module. Async functions come with actuators and perform in the same way as ordinary functions

g()// Prints hello async A hello async B
Copy the code

Async means that an asynchronous operation is being performed in a function, and await means that the following expression needs to wait for the result

The return value is promise