?? 內(nèi)容速覽 ??
- 題目和答案
- 輸出解釋
- 再談?wù)刟sync/await
- 最新的v8和谷歌瀏覽器的正確輸出
專注前端與算法的系列干貨分享,歡迎關(guān)注(???):
「微信公眾號(hào):心譚博客」| xin-tan.com | GitHub
1. 題目和答案
故事還是要從下面這道面試題說(shuō)起:請(qǐng)問(wèn)下面這段代碼的輸出是什么?
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輸出順序被“提前”了,請(qǐng)看官耐心慢慢看。
2. 流程解釋
邊看輸出結(jié)果,邊做解釋吧:
- 正常輸出
script start - 執(zhí)行
async1函數(shù),此函數(shù)中又調(diào)用了async2函數(shù),輸出async2 end。回到async1函數(shù),遇到了await,讓出線程。 - 遇到
setTimeout,扔到下一輪宏任務(wù)隊(duì)列 - 遇到
Promise對(duì)象,立即執(zhí)行其函數(shù),輸出Promise。其后的resolve,被扔到了微任務(wù)隊(duì)列 - 正常輸出
script end - 此時(shí),此次
Event Loop宏任務(wù)都執(zhí)行完了。來(lái)看下第二步被扔進(jìn)來(lái)的微任務(wù),因?yàn)?code>async2函數(shù)是async關(guān)鍵詞修飾,因此,將await async2后的代碼扔到微任務(wù)隊(duì)列中 - 執(zhí)行第4步被扔到微任務(wù)隊(duì)列的任務(wù),輸出
promise1和promise2 - 執(zhí)行第6步被扔到微任務(wù)隊(duì)列的任務(wù),輸出
async1 end - 第一輪EventLoop完成,執(zhí)行第二輪EventLoop。執(zhí)行
setTimeout中的回調(diào)函數(shù),輸出setTimeout。
3. 再談async和await
細(xì)心的朋友肯定會(huì)發(fā)現(xiàn)前面第6步,如果async2函數(shù)是沒(méi)有async關(guān)鍵詞修飾的一個(gè)普通函數(shù)呢?
// 新的async2函數(shù)
function async2() {
console.log('async2 end')
}
輸出結(jié)果如下所示:
script start
async2 end
Promise
script end
async1 end
promise1
promise2
setTimeout
不同的結(jié)果就出現(xiàn)在前面所說(shuō)的第6步:如果await函數(shù)后面的函數(shù)是普通函數(shù),那么其后的微任務(wù)就正常執(zhí)行;否則,會(huì)將其再放入微任務(wù)隊(duì)列。
4. 其實(shí)是V8引擎的BUG
看到前面,正常人都會(huì)覺(jué)得真奇怪?。ǖ前凑丈厦娴脑E竅倒也是可以理解)
然而V8團(tuán)隊(duì)確定了這是個(gè)bug(很多強(qiáng)行解釋要被打臉了),具體的PR請(qǐng)看這里。好在,這個(gè)問(wèn)題已經(jīng)在最新的Chrome瀏覽器中被修復(fù)了。
簡(jiǎn)單點(diǎn)說(shuō),前面兩段不同代碼的運(yùn)行結(jié)果都是:
script start
async2 end
Promise
script end
async1 end
promise1
promise2
setTimeout
await就是讓出線程,其后的代碼放入微任務(wù)隊(duì)列(不會(huì)再多一次放入的過(guò)程),就這么簡(jiǎn)單了。
更多系列文章
專注前端與算法的系列干貨分享,歡迎關(guān)注(???)
image
