何爲Event Loop
event loop是一個執行模型,是js異步運行的核心。js是一門單線程的語言,意味着js沒法進行多線程操做,可是js中的異步功能能夠徹底模擬多線程。javascript
宏隊列 macrotask
一些異步任務的回調會依次進入macro task queue,等待後續被調用,這些異步任務包括java
- setTimeout
- setInterval
- requestAnimationFrame (瀏覽器獨有)
- I/O
- UI rendering (瀏覽器獨有)
微隊列,microtask
一些異步任務的回調會依次進入micro task queue,等待後續被調用,這些異步任務包括:promise
- process.nextTick (Node獨有)
- Promise
- Object.observe
- MutationObserver
- Event Loop執行機制
這張圖將瀏覽器的Event Loop完整的描述了出來,如下是javascript執行代碼的具體順序
- 執行全局Script同步代碼
- 全局Script代碼執行完畢後,調用棧Stack會清空;
- 從微隊列中取出位於隊首的回調任務,放入調用棧Stack中執行,執行完後microtask queue長度減1;
- 繼續取出位於隊首的任務,放入調用棧Stack中執行,以此類推,直到把microtask queue中的全部任務都執行完畢。若是在執行microtask的過程當中,又產生了microtask,那麼會加入到隊列的末尾,也會在這個週期被調用執行;
- microtask queue中的全部任務都執行完畢,此時microtask queue爲空隊列,調用棧Stack也爲空;
- 取出宏隊列macrotask queue中位於隊首的任務,放入Stack中執行; 執行完畢後,調用棧Stack爲空;
- 重複第3-6個步驟;
要點
由此概括出兩個要點:瀏覽器
- 宏隊列macrotask一次只從隊列中取一個任務執行,執行完後就去執行微任務隊列中的任務;
- 微任務隊列中全部的任務都會被依次取出來執行,直到微任務隊列爲空;
接下來是一個代碼實例bash
console.log(1);
setTimeout(() => {
console.log(2);
Promise.resolve().then(() => {
console.log(3)
});
});
new Promise((resolve, reject) => {
console.log(4)
resolve(5)
}).then((data) => {
console.log(data);
})
setTimeout(() => {
console.log(6);
})
console.log(7);
複製代碼
輸出結果:1 4 7 5 2 3 6 整個流程爲:多線程
- 執行全局同步代碼(promise中在resolve或reject前的也算) 因此輸出1,4,7
- 執行微隊列代碼 此時的微隊列中的任務爲Promise中的resolve(5)則輸出5
- 執行宏隊列中的隊首任務(注意只執行一個宏任務),此時的隊首任務爲代碼中第一個setTimeOut,則輸出了2。在執行這個任務時又產生了一個新的微任務。
- 執行新產生的微隊列中的任務,因此輸出了3
- 微任務隊列爲空,宏隊列中還有一個任務,因而輸出6