
例子:下題你可能會認為100ms之後,由于a變成了false,是以while就中止了,實際不是這樣,因為JS是單線程的,是以進入while循環之後,沒有「時間」(線程)去跑定時器了,是以這個代碼跑起來是個死循環!
var
事件循環是JavaScript實作異步的具體解決方案,其中同步代碼直接執行;異步函數先放在異步隊列中,待同步函數執行完畢後,輪循執行異步隊列中的回調函數。
事件循環中,每進行一次循環操作稱為tick,每一個tick的任務處理模型關鍵步驟如下:
- 執行一個宏任務(棧中沒有就從事件隊列中擷取)
- 執行過程中如果遇到微任務,就将它添加到微任務的隊列中
- 宏任務執行完畢後,立即執行目前微任務隊列中的所有微任務(依次執行)
- 目前宏任務執行完畢,開始檢查渲染,然後GUI線程接管渲染
- 渲染完畢後,JS線程接續接管,開始下一個宏任務(從事件隊列中擷取)
(macro)task宏任務:包括script、setTimeout、I/O、UI互動等
micro task微任務:包括Promise.then、Mutation observer、process.nextTick(node.js環境等)。async/await和Promise實作延遲執行,并在每個task結束時執行。
在每一個事件循環之前,microtask隊列總是被清空。
代碼中出現setTimeout、async/await、Promise等函數正确的執行順序是怎樣的呢?
先看一道經典面試題目:
async
控制台運作結果為:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
注:上圖為Chrome75.0.3770.142執行結果截圖,如果浏覽器版本為Chrome61.0.3163.100(低于v73)則promise2先于async1 end列印(最新版本的firefox火狐亦是如此)。
分析執行過程流程圖:
"執行整體代碼"開始後掃到task放入task queue,掃到微任務放入micro task queue。
分析要點主要記住3點:
(1)Promise中的異步展現在then和catch中,故寫在Promise中的代碼是被當做同步任務立即執行的;
(2)而在async/await中,在出現await之前其代碼也是立即執行的。帶async關鍵字的函數僅僅是把return值包裝成promise傳回,其他并無不同之處;
(3)await是讓出線程的标志:await後面的表達式會先執行一遍(await等的是右側表達式的結果),将await語句之後的代碼加入到micro task中,然後就會跳出整個async函數來執行後續代碼。
用上例方法來分析另一道例題:
例2:
setTimeout(() => console.log('setTimeout1'), 0);
setTimeout(() => {
console.log('setTimeout2');
Promise.resolve().then(() => {
console.log('promise2');
Promise.resolve().then(() => {
console.log('promise3');
})
console.log(5)
})
setTimeout(() => console.log('setTimeout4'), 0);
}, 0);
setTimeout(() => console.log('setTimeout3'), 0);
Promise.resolve().then(() => {
console.log('promise1');
})
最後,我們再來一道在node中的異步題目吧:
async
(macro)task宏任務:包括script、setTimeout、I/O、UI互動、setImmediate(nodejs環境中)等 micro task微任務:包括Promise.then、Mutation observer、process.nextTick(node.js環境等)。async/await和Promise實作延遲執行,并在每個task結束時執行。在每一個事件循環之前,microtask隊列總是被清空。 windows下的node10.16.3運作結果如上圖,Mac的node12.6.0運作結果稍有出入:
具體表現在 async1 end和promise3孰先孰後、setImmediate和setTimeout3孰先孰後的差異。
本文參考連結:
8張圖讓你一步步看清 async/await 和 promise 的執行順序segmentfault.com 浏覽器和NodeJS中不同的Event Loop · Issue #234 · kaola-fed/bloggithub.com
Tasks, microtasks, queues and schedulesjakearchibald.com
更快的異步函數和 Promisev8.js.cn 令人費解的 async/await 執行順序juejin.im 用一道大廠面試題帶你搞懂事件循環機制mp.weixin.qq.com