💡 核心概念(清道夫鐵則):

「執行完一個宏任務(包含主程式)後,Event Loop 的第一優先要務就是去微任務隊列『掃地』。必須把微任務隊列徹底清空,才能去拿取下一個宏任務。」

1. 為什麼需要 Event Loop?

JavaScript 是單執行緒(Single-threaded)的語言,意味著它只有一個大腦,一次只能做一件事。 為了解決遇到耗時任務(如網路請求、計時器)會「卡死」畫面的問題,瀏覽器提供了一套協調機制,讓 JS 能達到非阻塞(Non-blocking)的異步操作,這套機制就是 Event Loop。

2. 三大核心運作區域

可以將瀏覽器環境想像成一個辦公室:

  1. Call Stack(調用堆疊)— 目前的辦公桌
  2. Web APIs — 委外處理部門
  3. Task Queues(任務隊列)— 等候室

3. 任務分類與優先級 (Task Classification)

在 Event Loop 中,「類別」比「先來後到」更重要。

任務類別 特性說明 常見的 API
🚀 微任務 (Microtasks) 「頭等艙 VIP」

優先級極高。只要隊伍裡有任務,就必須一次性全部清空,哪怕執行中又產生新的微任務。 | Promise.then / .catch / .finally

queueMicrotask

process.nextTick (Node.js)

MutationObserver | | 🚌 宏任務 (Macrotasks) | 「經濟艙」

優先級較低。每次 Event Loop 循環只會抓出最早進入等待的一個來執行。 | 整體 <script> 主程式

setTimeout / setInterval

DOM 事件 (click, input 等)

網路請求 (Ajax / fetch) |

4. 標準執行流程與底層真相 (Event Loop Tick)

一個完整的事件循環步驟,本質上是一個無窮無盡的「宏 ➔ 全部微 ➔ 宏 ➔ 全部微...」循環:

  1. 執行第一個宏任務(所謂的主程式):將網頁載入時的第一段 <script> 推入 Call Stack 執行直到結束。在底層引擎眼中,並沒有神聖不可侵犯的「主任務」,它就只是 Event Loop 誕生後接手的第一號宏任務。
  2. 清空微任務 (Microtask Checkpoint):宏任務(或主程式)清空後,Event Loop 立即檢查並徹底清空微任務隊列。
  3. 畫面渲染 (Rendering):如果瀏覽器判斷需要更新 UI,會在此時進行。
  4. 抽出下一個宏任務:從宏任務隊列的最前端,嚴格依照 FIFO(先進先出) 的原則,取出「最早進入等待的一個」任務執行。
  5. 絕對的執行至完成 (Run-to-completion):一旦開始執行新的宏任務或微任務,任何突發事件(如使用者瘋狂點擊、新腳本載入)都無法插斷執行。它們只能被降級成新的宏任務,乖乖排到隊列最後面。
  6. 重複循環:執行完該宏任務後,立刻回到步驟 2(再去清空微任務)。

5. 面試常見陷阱與誤區