前言
文关于
Event Loop
中async/await
的表现,文章中表述的观点,纯属个人的一些猜测与验证,如有不对,敬请斧正。
猜测1
由于
微任务
是后加入到任务队列
中的,且Promise
也属于微任务
,那么大胆猜测,async/await
的异步任务,也属于微任务。
console.log(111);
setTimeout(() => {
console.log(222);
}, 0);
(async () => {
console.log(333);
await console.log(444);
console.log(555);
})()
.then(()=>{
console.log(666);
});
console.log(777);
// 执行结果
// 111
// 333
// 444
// 777
// 555
// 666
// 222
分析
setTimeout
在 async 的上面,但是它最后执行,表明async/await
的异步属于微任务
;async
函数,会被包装成Promise
,所以console.log(6)
这一块的代码,也是微任务
;- 与
Promise
相同,在执行async
函数时,在遇到await
之前,均是同步的代码;
疑问:
await
后面的代码是怎样执行的?再遇到下一个 await
又是怎样的?
猜测2
await
后面的代码,async
中 执行到的await
后的代码是被当成一个整体来看的,这个整体属于一个微任务
。
console.log(111);
setTimeout(() => {
console.log(222);
}, 0);
(async () => {
console.log(333);
await console.log(444);
console.log(555);
await console.log(666);
console.log(777);
})()
.then(()=>{
console.log(888);
});
console.log(999);
new Promise((resolve) => {
resolve();
})
.then(() => {
console.log('promise');
});
// 执行结果
// 111
// 333
// 444
// 999
// 555
// 666
// promise
// 777
// 888
// 222
分析
从当前结果看, 999
之前的应该没有疑问,都是同步代码,需要考虑的时 await
后的代码执行逻辑。
- 先将代码拆分成块:
// awaitA 代码块 --- 执行了第一个 await 后面的代码
console.log(555);
await console.log(666);
console.log(777);
// awaitB 代码块 --- 执行了第二个 await 后面的代码
console.log(777);
// async.then 代码块 --- async 的 .then 代码块,它需要等到 async 函数执行完成。
.then(()=>{
console.log(888);
});
// promise 代码块
new Promise((resolve) => {
resolve();
})
.then(() => {
console.log('promise');
});
- 分析过程:
由上面的结论,现在得到任务队列中的有四个任务:awaitA 代码块
— 微任务;async.then 代码块
— 微任务;promise 代码块
— 微任务;setTimeout
— 宏任务;
先执行微任务:
按照 微任务
的 先进先出
规则,
执行 awaitA 代码块
,打印 555, 666
,此时,又遇到一个 await
, 则将第二个 await
后面的代码,也就是 awaitB 代码块
追加到 微任务
中;
继续执行 微任务
,此时执行 promise 代码块
,打印 promise
;
由于 async.then 代码块
这块比较特殊,它时等 async
执行完成后,才会被添加到队列中的,所以此时它还没有添加到队列中,所以现在执行第二个 await
后的代码块,也就是 awaitB 代码块
, 此时打印 777
;
当 async
函数中的代码执行完成后,async.then 代码块
的代码添加到微任务队列并执行,打印 888
;
最后在执行 setTimeout
,打印222
.
结论:
async
在 Event Loop
中,遇到 await
之前的代码,都属于同步代码,当遇到第一个 await
后,属于 aysnc
函数中的 await
后面的所有代码,都作为一个微任务,保存到任务队列中,当执行完成同步代码后,执行任务队列中的微任务
。
当执行 await
后面的 微任务
代码块时,如果内部还有 await
,后面的代码再继续被添加到 微任务队列
中,由于 微任务
的特性,所有 微任务
都执行完成后,再去执行 宏任务
,所以才会出现上面的情况。