Recently, I suddenly found a problem. The reason was that in the interview, there was a basic knowledge question, only a few answers were correct, the topic is as follows:

async function async1() {
  console.log('async1')
  await async2()
  console.log('async2')}async function async2() {
  console.log('async2')
}

async1()

new Promise((resolve, reject) = > {
  console.log('promise1')
  resolve()
}).then(res= > {
  console.log('promise2')})Copy the code

This is not difficult, but once async/await is mixed with promise, the error rate spikes, which is mainly due to poor understanding of async/await mechanism.

Understand this topic before, must first be familiar with the Event Loop (the Event Loop), the micro macro tasks and tasks for the Event Loop, recommend a look at the url: jakearchibald.com/2015/tasks-… , the internal animation step by step to perform the process of loading and unloading the stack.

To understand async/await, we should first understand how the function will change if the async flag is added in front of it:

async function asynctest() {
    let result = false
    console.log(result, 'result')
    return result
}
Copy the code

function test() {
    let result = false
    console.log(result, 'result')
    return result
}
Copy the code

As shown above, the async flag precedes the function, and the return value is wrapped in a Promise.

Instead of the async tag, what if the same effect were achieved:

function test() {
    let result = false
    console.log(result, 'result')
    return Promise.resolve(result)
}
Copy the code

// PS
Promise.resolve(false) = = =new Promise(res= > res(false))
Copy the code

Would it change if we added await:

async function asynctest() {
    let result = await false
    console.log(result, 'result')
    return result
}
Copy the code

This looks the same as not adding ‘await’, so change ‘await’ to an asynchronous function and let’s see:

function syncFn() {
    return new Promise((res) = > {
        setTimeout(() = > {
            res('syncFn')},1000)})}async function asynctest() {
    let result = await syncFn()
    console.log(result, 'await result')
    return result
}
Copy the code

If async is added to the front of a function, the return result of the function will be wrapped with a Promise, and await can be added to the front of an expression, blocking the stack until the expression is completed. To await is simply to get the value returned by the expression. Therefore, if async is written in the style of Promise, it can be written like this.

async function asynctest() {
    let result = await syncFn()
    console.log(result, 'await result')
    return result
}

/ / rewrite
function asynctest() {
    let result = new Promise(res= > {
        let ret = syncFn()
        res(ret)
    }).then(res= > {
        console.log(result, 'await result')
        return res
    })
    return result
}
Copy the code

This is rewritten using only Promise, which is not easy to understand in some scenarios, such as:

function syncFn() {
    return new Promise((res) = > {
        setTimeout(() = > {
            res('syncFn')},1000)})}async function test(){
    for (let i = 0; i < 10; i++){
        let res = await syncFn()
        console.log(res, i)
    }
}
Copy the code

Await can block a for loop, which, if written with a promise, would have to be written as a hell callback:

function syncFn() {
    return new Promise((res) = > {
        setTimeout(() = > {
            res('syncFn')},1000)})}function asynctest(i) {
    if (i > 9) return 
    let result = new Promise(res= > {
        let ret = syncFn()
        res(ret)
    }).then(res= > {
        console.log(res, i)
        asynctest(i + 1)
        return res
    })
}
Copy the code

For the blocking function scenario, it should be easy to think of generate:

function *generate() {
    for (let i = 0; i < 5; i++) {
        let res = yield i
        console.log(res)
    }
    console.log('end')}Copy the code

So you can combine generate with a promise:

Write a self-executing generator function:

// Generator self-effector
function asyncToGenerator(genFn) {
  return new Promise((resolve, reject) = > {
    let gen = genFn()
    function step(key, arg) {
      let info = {}
      try {
        info = gen[key](arg);
      } catch (error) {
        reject(error)
        return
      }
      if (info.done) {
        resolve(info.value)
      } else {
        return Promise.resolve(info.value).then(v= > {
          return step('next', v)
        }, (error) = > {
          return step('throw', error)
        })
      }
    }
    step('next')})}Copy the code

Then test it out:

let test = function () {
  let ret = asyncToGenerator(function* () {
    for (let i = 0; i < 10; i++) {
      let result = yield syncFn();
      console.log(result, i); }})return ret
}
Copy the code