👇 内容速览 👇
- 题目和答案
- 输出诠释
- 再谈谈async/await
- 最新的v8和谷歌浏览器的准确输出
1. 题目和答案
故事照样要从下面这道口试题提及:叨教下面这段代码的输出是什么?
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')
上述,在Chrome 66
和node v10
中,准确输出是:
script start
async2 end
Promise
script end
promise1
promise2
async1 end
setTimeout
注重:在新版本的浏览器中,
await
输出递次被“提早”了,请看官耐烦逐步看。
2. 流程诠释
边看输出效果,边做诠释吧:
- 一般输出
script start
- 实行
async1
函数,此函数中又调用了async2
函数,输出async2 end
。回到async1
函数,碰到了await
,让出线程。 - 碰到
setTimeout
,扔到下一轮宏使命行列 - 碰到
Promise
对象,马上实行其函数,输出Promise
。厥后的resolve
,被扔到了微使命行列 - 一般输出
script end
- 此时,此次
Event Loop
宏使命都实行完了。来看下第二步被扔进来的微使命,由于async2
函数是async
关键词润饰,因而,将await async2
后的代码扔到微使命行列中 - 实行第4步被扔到微使命行列的使命,输出
promise1
和promise2
- 实行第6步被扔到微使命行列的使命,输出
async1 end
- 第一轮EventLoop完成,实行第二轮EventLoop。实行
setTimeout
中的回调函数,输出setTimeout
。
3. 再谈async和await
仔细的朋侪肯定会发明前面第6步,假如async2
函数是没有async
关键词润饰的一个一般函数呢?
// 新的async2函数
function async2() {
console.log('async2 end')
}
输出效果以下所示:
script start
async2 end
Promise
script end
async1 end
promise1
promise2
setTimeout
差别的效果就出如今前面所说的第6步:假如await函数背面的函数是一般函数,那末厥后的微使命就一般实行;不然,会将其再放入微使命行列。
4. 实际上是V8引擎的BUG
看到前面,一般人都邑以为真新鲜!(然则根据上面的窍门倒也是能够明白)
但是V8团队肯定了这是个bug(许多强行诠释要被打脸了),详细的PR请看这里。幸亏,这个题目已经在最新的Chrome浏览器中被修复了。
简朴点说,前面两段差别代码的运转效果都是:
script start
async2 end
Promise
script end
async1 end
promise1
promise2
setTimeout
await
就是让出线程,厥后的代码放入微使命行列(不会再多一次放入的历程),就这么简朴了。
更多系列文章
《前端学问系统》
《设想形式手册》
《Webpack4渐进式教程》