🔄
イベントループ — setTimeout(fn, 0)が即座に実行されない理由
Call Stack、Task Queue、Microtask Queueの実行順序
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// 出力: 1, 4, 3, 2
0msタイムアウトなのにPromiseの後に出るのはなぜ?イベントループの実行順序のせいだ。
3つのキュー
Call Stack — 現在実行中の関数。同期コードはここで順次実行。
Microtask Queue — Promise.then、MutationObserver、queueMicrotask。Call Stackが空になると全Microtaskを完全に空にするまで実行。Task Queueより優先。
Task Queue(Macro Task) — setTimeout、setInterval、I/Oコールバック、requestAnimationFrame。Microtask完全排出後に1つずつ実行。
V8の実装
V8自体はイベントループを実装しない。ブラウザではlibevent/OSイベントループが、Node.jsではlibuvが担当。V8はCall StackとMicrotask Queueのみ管理。
キーポイント
1
Call Stackの同期コードが全て終わってから非同期コールバックが実行される
2
Microtask(Promise.then)がTask(setTimeout)より常に先に実行
3
Microtask Queueは全て空になるまで実行 — 途中にTaskが挟まらない
4
V8はCall Stack + Microtaskのみ管理、イベントループはブラウザ/libuvが担当
ユースケース
非同期実行順序デバッグ — なぜこのコールバックがあれより先に実行されるか
UI応答性 — 重い作業をsetTimeoutで分割してレンダリング機会を確保