Web
Javascript Event Loop
Javascript Engine and Runtime
Engine 用來編譯和執行 Javascript,而 Runtime 則是提供完整的環境讓 engine 執行。 舉例來說:
- google chrome 的 runtime 使用 V8 engine 並提供 web API 讓 engine 可以操作 DOM 等
- nodejs 同樣使用 V8 engine 並提供
fs
等模組讓 engine 可以和文件互動等
而 event loop 就是由 runtime 提供的一個功能,讓原本是 single-threaded language 的 Javascript 可以「看起來像」執行 asynchronous 的操作。
Runtime and Event Loop

javascript runtime 架構
- 每次有 function 被呼叫時,就會建立該 function 的 frame (包含它的參數、變數等),並 push 到 stack 裡面執行,當 return 時才會被 pop 出來。
- 當呼叫到 Web API 時,還是會建立 frame,不過馬上 return 交給 runtime 來去執行 (所以此時 stack 裡面已經沒有該 frame),當 runtime 執行完後會呼叫 callback function,並將其放入 task queue (或是 microtask queue)。
- 每當 stack 清空後,event loop 就會將 task queue 的第一個 task 移到 stack 內去執行。
- 雖然說是 queue,不過實際上並非 FIFO,大多數的瀏覽器都會對 task 做 priority
- 每當一個 task (marcotask) 被執行完後,會先將 microtask queue 內的所有 task 都放到 stack 執行完後接著執行 rendering,結束後才繼續執行其他的 task
- microtask queue 是 FIFO
Marcotask and Microtask
microtask 包含:
promise.then/catch/finally
的 callback function (promise
內的程式不會)async
內的第一個await
之後的程式MutationObserver()
queueMicrotask()
marcotask 其實就是一般的 task
microtask 和 microtask queue 的出現有一部份是為了因應 promise (ES2015) 的出現,因為 promise 在 callback 的時候需要確保執行的順序以及上下文。 舉例來說
console.log("Start");
setTimeout(() => console.log("setTimeout"), 0);
Promise.resolve().then(() => console.log("Promise callback"));
console.log("End");
如果沒有 microtask queue 的話,輸出可能會是 Start -> End -> setTimeout -> Promise callback
,也就是說 .then
的內容被放到了下一個 event loop 才執行,上下文可能已經不同造成邏輯錯誤。
同時與 DOM 相關的操作 (MutationObserver()
) 也被納入 microtask 因為如果沒有在 render 前執行可能會導致 render 的結果不一致。
References
- https://developer.mozilla.org/en-US/notes/Web/JavaScript/Event_loop
- https://www.youtube.com/watch?v=8aGhZQkoFbQ
- https://www.youtube.com/watch?v=eiC58R16hb8
- https://pjchender.dev/javascript/js-event-loop-stack-queue/#%E6%8A%8A%E5%90%8C%E6%A8%A3%E7%9A%84%E8%A7%80%E5%BF%B5%E5%A5%97%E5%88%B0-ajax-request
- https://gcdeng.com/series/Javascript/javascript-deep-dive-into-event-loop#overview
- https://realdennis.medium.com/%E6%80%8E%E9%BA%BC%E7%90%86%E8%A7%A3-microtask-macrotask-7754939b3c2c
- https://stackoverflow.com/questions/66190571/what-was-the-motivation-for-introducing-a-separate-microtask-queue-which-the-eve
- https://pjchender.dev/javascript/note-event-loop-microtask/