Skip to main content

理解 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 / .catch
  • process.nextTick (Node.js)
  • MutationObserver

如此一來,queue 又一分為二 : macro queue、micro queue,也就是存放兩種不同性質的 queue,其順序如下

  1. 當宏任務執行完畢後 (整體 script 執行也算宏任務),會去檢查微任務 queue 有沒有東西
  2. 若 micro queue 有微任務在等待,就一口氣執行完目前所有在序列的微任務,直到為空
  3. 渲染 ui
  4. 繼續下一個宏任務

範例

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 放入微任務 queue
    • setTimeout 開始計時,計時完 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