Event Loop:為什麼 JS 是單執行緒?
JavaScript 只有一條執行緒
❌ 錯誤理解:setTimeout 會開新執行緒
✅ 正確理解:setTimeout 把回呼放進佇列,等主執行緒空了才執行
執行模型
┌─────────────────┐
│ Call Stack │ ← 目前正在執行的程式碼
│ (執行堆疊) │
└────────┬────────┘
↓ 空了才去拿
┌─────────────────┐
│ Microtask Queue │ ← Promise.then、queueMicrotask(優先)
└────────┬────────┘
↓ 微任務清空了才去拿
┌─────────────────┐
│ Macrotask Queue │ ← setTimeout、setInterval、I/O、事件
└─────────────────┘
經典面試題
console.log('1');
setTimeout(() => {
console.log('2');
}, 0);
Promise.resolve().then(() => {
console.log('3');
});
console.log('4');
// 輸出順序:1, 4, 3, 2
// 1:同步,直接執行
// 4:同步,直接執行
// 3:微任務(Promise),優先於宏任務
// 2:宏任務(setTimeout),最後執行
為什麼不做成多執行緒?
問題:兩個執行緒同時操作 DOM 會怎樣?
執行緒 A:刪除一個按鈕
執行緒 B:改這個按鈕的文字
→ 衝突!
解決方案:
1. 加鎖(Lock)→ 太複雜,Web 開發者不想管
2. 保持單執行緒 → 簡單、不會有競爭條件
但需要非同步機制(Event Loop)避免 I/O 卡住 UI
Web Workers(真正的多執行緒)
// 需要 CPU 密集計算時
const worker = new Worker('heavy-calc.js');
worker.postMessage({ data: bigArray });
worker.onmessage = (e) => {
console.log('計算結果:', e.data);
};
// Worker 在背景執行緒跑,不會卡住 UI
// 但 Worker 不能存取 DOM
記住:JS 是單執行緒 + Event Loop 處理非同步。不是沒有能力做多執行緒,而是刻意設計成這樣讓 DOM 操作更安全。