FIG-004

JavaScriptはなぜ「待てる」のか — イベントループ

ブラウザ 2026.06.12 公開 読了 約14分

JavaScriptはシングルスレッドです。一度に1つのことしかできません。それなのに、タイマーを待ちながら、通信の返事を待ちながら、画面は固まらずに動き続けます。この「待てる」仕組みの正体がイベントループです。

下の図1では、4行のコードを1ステップずつ実行しながら、コールスタックと2つのキューがどう動くかを観察できます。その前に1つだけ予想してみてください — A・B・C・Dはどの順番で出力されるでしょうか?

CODE — 実行するコード
1 console.log('A');
2 setTimeout(() => console.log('B'), 0);
3 Promise.resolve().then(() => console.log('C'));
4 console.log('D');
CONSOLE — 出力
(まだ出力はありません)
CALL STACK — 実行中の仕事
MICROTASKS — マイクロタスク(優先)
TASK QUEUE — タスクキュー
STEP 1 / 9
図1 — イベントループのステップ実行(コールスタックと2つのキュー)

ルールは3つだけ

図1の動きは、たった3つのルールで説明できます。(1) コールスタックにある仕事を上から順に実行する。(2) スタックが空になったら、まずマイクロタスクキューを空になるまで全部実行する。(3) それからタスクキューの先頭を1つだけ取り出して実行する。あとはこの(2)と(3)をぐるぐる繰り返す — このループがイベントループです。

大事なのは、setTimeout(..., 0) の「0ミリ秒」でさえすぐには実行されないことです。コールバックはあくまでキューに並ぶだけで、いま実行中のコードが最後まで終わってスタックが空くのを待ちます。だからこそ、同期コードの途中に割り込まれる心配がない代わりに、重い処理でスタックを長く占領すると、キューの仕事が動けず画面が固まります。

用語ミニ辞書
コールスタック
「いま実行中の仕事」の積み重ね。JSはこれが1本しかない(シングルスレッド)。
タスクキュー
setTimeoutやクリックイベントのコールバックが並ぶ行列。1周につき1つだけ実行される。
マイクロタスク
Promiseの.thenなどが並ぶ優先行列。タスクキューより先に、毎回空になるまで実行される。

まとめ

JavaScriptが「待てる」のは、待ち仕事を自分で抱え込まず、ブラウザに任せて、できあがったらキューに並んでもらうからでした。出力順が A→D→C→B になる理由も、「同期コードが先、次にマイクロタスク全部、最後にタスク1つ」というループの順番そのものです。async/await も中身はPromiseなので、この図のマイクロタスクの動きが分かっていれば怖くありません。