promise,async/await执行顺序

209 阅读3分钟

1,先看看经典面试题

先贴一个经典面试题,执行结果可能跟具体的chrome版本有点不同。

      async function async1() {
        console.log('async1 start');
        await async2();
        console.log('async1 end');
      }
      async function async2() {
        console.log('async2');
      }
      console.log('script start');
      setTimeout(function () {
        console.log('setTimeout');
      }, 0);
      async1();
      new Promise((resolve) => {
        console.log('promise0');
        resolve();
      })
        .then(() => {
          console.log('promise1');
        })
        .then(() => {
          console.log('promise2');
        });
      console.log('script end');

执行结果:

script start
async1 start
async2
promise0
script end
async1 end
promise1
promise2
setTimeout

分析这段代码的基础是js事件的宏任务和微任务队列,以及promise async/await的使用。

1,首先js的线程从头开始一步步执行同步代码,执行打印:

script start
async1 start

3,然后执行遇到await async2(),一般来说遇到awit的时候,会让出当前线程,但是await的执行顺序是从右向左执行的过程,所以会优先执行async2函数的,打印:

 async2

然后返回一个promise对象,async2函数返回之后,遇到await之后,会将promise对象放到微任务队列中,那么这个promise对象到底是什么呢?想一想我们平时执 new Promise().then(res=>{})一般都是promise返回一个不是pending的状态之后,会讲then里的res=>{}对应函数放到微任务队列中去,那么async2执行之后,就相当于返回一个值为undefined的promise对象,那么,此刻就相当于把(undefined)=>{resolved(unfined)}函数放到一个微任务队列中,然后await让出主线程。继续之后之后的同步代码。

4,Promise中的代码也是同步代码,所以会打印,

promise0

因为立即执行了resolve,,随意此刻Promise的状态是resoled状态,他的then函数会会放到微任务队列等到之后执行,也就是将() => {console.log('promise1');}放到微任务队列

5,最后执行console.log('script end');,打印:

script end

到此,所有的同步代码已经完成。

6,js线程开始去取微任务队列中的任务执行,async执行之后放进去的(undefined)=>{resolved(unfined)}会得到执行,await等待结果返回,会执行之后的代码,于是打印:

async1 end

7,接着执行下一个微任务:打印:

promise1

由于promise1执行之后,还是会返回rosloved状态的promise,随意此时,这个promise的then函数,也就是() => {console.log('promise2'); }会放到微任务队列,,js线程再次取微任务的时候,执行打印:

promise2

8,所有的微任务都执行完成之后,会去取宏任务队列依次执行,打印:

setTimeout

稍微变异一下

 async function async1() {
        console.log('async1 start');
        await async2()
          .then((res) => {
            console.log('res1');
          })
          .then((res) => {
            console.log('res2');
          });
        console.log('async1 end');
      }
      async function async2() {
        console.log('async2');
      }
      console.log('script start');
      setTimeout(function () {
        console.log('setTimeout');
      }, 0);
      async1();
      new Promise((resolve) => {
        console.log('promise0');
        resolve();
      })
        .then(() => {
          console.log('promise1');
        })
        .then(() => {
          console.log('promise2');
        });
      console.log('script end');

这段代码相对于上面的代码,只是在async1 的 await的函数中多加了两个then函数,我们来看一下执行结果:

script start
async1 start
async2
promise0
script end
res1
promise1
res2
promise2
async1 end
setTimeout

在上面的经典题中可能比较难理解的还是async1 endpromise1的顺序,我们借着这个变题再深刻理解一下,async1中的await 后的async2执行完成时候,其实是将res1的函数放到异步队列中去了,而之前没有定义async2()的then的时候,其实就相当于把(undefined)=>{resolved(undefined)}当成一个微任务。理清了这个逻辑,那么接下来的执行顺序应该都能清楚了。