LuckyWinty / fe-weekly-questions

A pro to record some interview questions every week...
MIT License
341 stars 34 forks source link

执行下面代码,输出什么? #17

Open LuckyWinty opened 4 years ago

LuckyWinty commented 4 years ago

console.log('script start')

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

setTimeout(function() { console.log('setTimeout') }, 0)

new Promise(resolve => { console.log('Promise') resolve() }) .then(function() { console.log('promise1') }) .then(function() { console.log('promise2') })

console.log('script end')

LuckyWinty commented 4 years ago

理论上输出:

script start => async2 end => Promise => script end => promise1 => promise2 => async1 end => setTimeout

新版的chrome浏览器中不是如上打印的,因为chrome优化了,await变得更快了,输出为:

// script start => async2 end => Promise => script end => async1 end => promise1 => promise2 => setTimeout

但是这种做法其实是违法了规范的,当然规范也是可以更改的,这是 V8 团队的一个 PR ,目前新版打印已经修改。

LuckyWinty commented 4 years ago

我们可以分2种情况来理解:

  1. 如果await 后面直接跟的为一个变量,比如:await 1;这种情况的话相当于直接把await后面的代码注册为一个微任务,可以简单理解为promise.then(await下面的代码)。然后跳出async1函数,执行其他代码,当遇到promise函数的时候,会注册promise.then()函数到微任务队列,注意此时微任务队列里面已经存在await后面的微任务。所以这种情况会先执行await后面的代码(async1 end),再执行async1函数后面注册的微任务代码(promise1,promise2)。

  2. 如果await后面跟的是一个异步函数的调用,比如上面的代码,将代码改成这样:

    
    console.log('script start')

async function async1() { await async2() console.log('async1 end') } async function async2() { console.log('async2 end') return Promise.resolve().then(()=>{ console.log('async2 end1') }) } async1()

setTimeout(function() { console.log('setTimeout') }, 0)

new Promise(resolve => { console.log('Promise') resolve() }) .then(function() { console.log('promise1') }) .then(function() { console.log('promise2') })

console.log('script end')


此时执行完awit并不先把await后面的代码注册到微任务队列中去,而是执行完await之后,直接跳出async1函数,执行其他代码。然后遇到promise的时候,把promise.then注册为微任务。其他代码执行完毕后,需要回到async1函数去执行剩下的代码,然后把await后面的代码注册到微任务队列当中,注意此时微任务队列中是有之前注册的微任务的。所以这种情况会先执行async1函数之外的微任务(promise1,promise2),然后才执行async1内注册的微任务(async1 end).