喂!我是 Wei

Front-End Engineer

Be a Problem Solver.

⌘K

導覽

所有文章緣起互動小功能

文章分類

目錄
JavaScript 是單執行緒,為什麼能做非同步?Microtask 和 Macrotask經典執行順序題setTimeout 0 為什麼不是立刻執行?async / await 怎麼理解?Microtask 太多會怎樣?常見追問requestAnimationFrame 在哪裡?fetch callback 是 microtask 嗎?為什麼長任務會讓畫面卡住?面試回答模板

相關文章

前端 CI/CD 與正式環境除錯:從 Pull Request 到事故排查

2026年6月24日

即時資料怎麼選?Polling、SSE、WebSocket 比較

2026年6月23日

前端系統設計:如何拆元件、資料流與大型專案架構?

2026年6月22日

最新文章
全部 →
前端 CI/CD 與正式環境除錯:從 Pull Request 到事故排查
2026-06-24
即時資料怎麼選?Polling、SSE、WebSocket 比較
2026-06-23
前端系統設計:如何拆元件、資料流與大型專案架構?
2026-06-22
無障礙不是加 ARIA:語意化 HTML、鍵盤操作與焦點管理
2026-06-21
CSS 與 RWD 面試整理:Flexbox、Grid、定位與層疊脈絡
2026-06-19
← 返回文章列表

JavaScript Event Loop:Promise 和 setTimeout 誰先執行?

2026年6月13日·約 4 分鐘閱讀·
前端面試系列JavaScriptEvent Loop

Event Loop 是 JavaScript 基礎面試最常見的執行順序題。

它不只是背「Promise 比 setTimeout 快」,而是要理解 JavaScript 如何在單一主執行緒上協調同步程式、非同步結果與畫面更新。


JavaScript 是單執行緒,為什麼能做非同步?

JavaScript 一次只會在 Call Stack 執行一段程式。

計時器、網路請求、DOM event 等能力由瀏覽器環境處理。完成後,callback 會進入對應 queue,等待 Event Loop 安排回到 Call Stack。

Call Stack
  ↕
Event Loop
  ↙        ↘
Microtask   Task Queue
Promise     setTimeout

Microtask 和 Macrotask

常見 microtask:

  • Promise.then / catch / finally
  • queueMicrotask
  • MutationObserver

常見 task / macrotask:

  • setTimeout
  • setInterval
  • UI event
  • message event

一輪同步程式執行完後,Event Loop 會先清空 microtask queue,再進入下一個 task。


經典執行順序題

console.log("A");
 
setTimeout(() => {
  console.log("B");
}, 0);
 
Promise.resolve().then(() => {
  console.log("C");
});
 
console.log("D");

輸出:

A
D
C
B

原因:

  1. 同步的 A、D 先執行
  2. Promise callback 進 microtask queue
  3. setTimeout callback 進下一輪 task queue
  4. 同步程式結束後先清空 microtask,所以 C 先於 B

setTimeout 0 為什麼不是立刻執行?

0 代表最早可以被排程的延遲,不代表插隊執行。

callback 還是要等待:

  • 目前 Call Stack 清空
  • microtask queue 清空
  • Event Loop 輪到下一個 task

如果主執行緒被長任務卡住,計時器也會延後。

setTimeout(() => console.log("timer"), 0);
 
const start = Date.now();
while (Date.now() - start < 2000) {
  // block main thread
}

timer 至少要兩秒後才有機會執行。


async / await 怎麼理解?

await 後面的程式可以理解為接在 Promise microtask 裡繼續執行。

async function run() {
  console.log("1");
  await Promise.resolve();
  console.log("2");
}
 
console.log("3");
run();
console.log("4");

輸出:

3
1
4
2

await 前仍是同步執行,await 後則排到 microtask。


Microtask 太多會怎樣?

Event Loop 會先清空 microtask queue。如果程式持續建立 microtask,下一個 task 和畫面更新可能一直沒有機會執行。

function loop() {
  queueMicrotask(loop);
}
 
loop();

這可能造成頁面卡住,稱為 microtask starvation。


常見追問

requestAnimationFrame 在哪裡?

requestAnimationFrame 會在瀏覽器準備繪製下一幀前呼叫,適合做和畫面更新同步的動畫,不等同一般 setTimeout task。

fetch callback 是 microtask 嗎?

網路請求由瀏覽器處理;Promise resolve 後,.then callback 會以 microtask 執行。

為什麼長任務會讓畫面卡住?

JavaScript 執行、style/layout、paint 都會競爭主執行緒。同步運算長時間佔住 stack,瀏覽器就無法回應輸入或更新畫面。


面試回答模板

JavaScript 在瀏覽器主執行緒上透過 Event Loop 處理非同步工作。同步程式先在 Call Stack 執行,結束後會先清空 microtask queue,例如 Promise 和 queueMicrotask,再處理下一個 task,例如 setTimeout。setTimeout 0 不是立即執行,只是最早能進入下一輪排程。理解 Event Loop 也能解釋為什麼長任務會阻塞互動和畫面更新。

分享:XLinkedIn
← 上一篇TypeScript 面試必懂:any、unknown、never、泛型與型別收斂
下一篇 →前端測試怎麼分層?Unit、Integration、E2E 的取捨