理解 Event Loop 3 - Macro & Micro
前言
micro task 跟 macro task 是 event loop 的最後一塊拼圖,我們可以將任務區分為 macro ( 宏觀 ) 與 micro ( 微觀 ),因為這兩個英文單字看起來實在太像了,後面盡量先以中文代稱
宏任務 Macro Task
- script ( JavaScript 整體程式碼 )
setTimeout
setInterval
setImmediate
- I/O UI 互動相關
微任務 Micro Task
Promise
的 .then / .catchprocess.nextTick
(Node.js)MutationObserver
如此一來,queue 又一分為二 : macro queue、micro queue,也就是存放兩種不同性質的 queue,其順序如下
- 當宏任務執行完畢後 (整體 script 執行也算宏任務),會去檢查微任務 queue 有沒有東西
- 若 micro queue 有微任務在等待,就一口氣執行完目前所有在序列的微任務,直到為空
- 渲染 ui
- 繼續下一個宏任務
範例
console.log("Start");
Promise.resolve().then(() => {
console.log("Promise");
});
setTimeout(() => {
console.log("setTimeout");
}, 0);
console.log("End");
// output:
// Start
// End
// Promise
// setTimeout
- 一個宏任務開始 ( 執行整體 script )
- 印出
console.log("Start")
Promise.resolve().then()
then() 裡面的 callback 放入微任務 queuesetTimeout
開始計時,計時完 callback 放入宏任務 queue- 印出
console.log("End")
- 一個宏任務結束 ( 整體 script 執行完畢 )
- 印出
- 開始執行微任務 queue
- 印出
console.log("Promise")
- 印出
- 開始執行下一個宏任務 ( 在宏任務 queue 裡的任務)
console.log("setTimeout")
魔王範例
console.log(1);
setTimeout(() => {
console.log(2);
Promise.resolve().then(() => {
console.log(3);
});
}, 0);
new Promise((resolve, reject) => {
console.log(4);
resolve(5);
}).then((data) => {
console.log(data);
});
setTimeout(() => {
console.log(6);
}, 0);
console.log(7);
試著回答看看 console.log 分別會印出什麼
點擊看答案
1 -> 4 -> 7 -> 5 -> 2 -> 3 -> 6
小結
微任務會穿插在每個宏任務之間
又可以說,以第一次執行來看,微任務 queue 會優先於 宏任務 queue
Reference
聊聊 JavaScript 异步中的 macrotask 和 microtask
JS 原力覺醒 Day15 - Macrotask 與 MicroTask
Tasks, microtasks, queues and schedules
淺談 JavaScript 中的 Event Queue、Event Table、Event Loop 以及 Event Task