- ブラウザURL入力今ここ
- DNS名前→IP
- ルータ経路選択
- ロードバランサ振り分け
- Nginx受け口
- アプリ処理
- DB保存
同じブラウザの中で、JavaScript・描画・ネットワーク・ユーザー操作をどう並べるかを決めている仕組みを見ます。仕様の逐語は2026年9月13日に取得したものです。
まず結論
「タスクキュー」は名前に queue と付いていますが、HTML仕様の定義は **set(集合)** です。仕様は理由まで書いています。先頭から取り出すのではなく「最初の *実行可能な* タスク」を取るからです。一方でマイクロタスクキューは本物の queue で、仕様は "The microtask queue is not a task queue." と明言しています。
`setTimeout(fn, 0)` が0msにならない主因はクランプではありません。4msへのクランプは「入れ子レベルが5を超え、かつ指定値が4未満」のときだけです。そもそもタイマーはタスクとして積まれ、順番待ちをします。
1つのタスクを実行し終えた時点で、マイクロタスクが3つ溜まっていました。HTML仕様の処理モデルでは次に何が起きるでしょうか。
当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。
仕様が言う「イベントループ」は、JSを回す仕組みではない
イベントループを「JavaScriptを順番に実行する仕組み」と覚えている人は多いと思います。HTML仕様の定義はもう少し広いものです。
To coordinate events, user interaction, scripts, rendering, networking, and so forth, user agents must use event loops as described in this section. Each agent has an associated event loop, which is unique to that agent.
並んでいるのは、イベント・ユーザー操作・スクリプト・レンダリング・ネットワークです。描画や通信まで含めて**協調させる(coordinate)**調停役として定義されています。
もう一文。
Event loops do not necessarily correspond to implementation threads. For example, multiple window event loops could be cooperatively scheduled in a single thread.
「1イベントループ = 1スレッド」という説明をよく見ますが、仕様は「必ずしも対応しない」と明言しています。
task queue は queue ではない
本題です。仕様の §8.1.7.1 にこう書かれています。
An event loop has one or more task queues. A task queue is a set of tasks.
集合です。しかも仕様は、なぜ集合なのかの理由まで書いています。
Task queues are sets, not queues, because the event loop processing model grabs the first runnable task from the chosen queue, instead of dequeuing the first task.
先頭から取り出す(dequeue)のではなく、最初の「実行可能な」タスクを取る。だから待ち行列ではなく集合だ、という理屈です。
そして、そのすぐ近くにこの一文が単独で置かれています。
The microtask queue is not a task queue.
仕様上のデータ構造 取り出し方 一度に処理する数task queue set(集合) 最初の runnable なもの 1つmicrotask queue queue(待ち行列) dequeuing(先頭から) 空になるまで全部─────────────────────────────────────────────────────────────────名前は似ているが、仕様は "The microtask queue is not a task queue." と明記
名前が似ているため同類に見えますが、構造も取り出し方も処理数も違います。
「タスクキューは待ち行列なので、先に積まれたタスクから順に取り出される」という説明をHTML仕様に照らすとどう評価できますか。
タスク1つ、そのあとマイクロタスク全部
処理モデル(§8.1.7.3)を逐語で並べます。
- ・取り出すのは「1つ」。仕様に「タスクキューを空にする」とは書かれていない
- ・マイクロタスクは「空になるまで」。実行中に積まれた分も同じループで処理される
差はステップ2の下位ステップ3と8の非対称にあります。タスクは1つだけ取り出され、「タスクキューを空にする」とは書かれていません。ところがマイクロタスクのチェックポイントはこうです。
While the event loop's microtask queue is not empty:
1つではなく全部です。しかも実行中に積まれた分も同じ条件判定に入るので、マイクロタスクの中でマイクロタスクを積み続ければ、そこから抜けられなくなります。
queueMicrotask に仕様が添えている説明も、この順序と一致しています。
This allows their code to run once the JavaScript execution context stack is next empty, which happens once all currently executing synchronous JavaScript has run to completion.
setTimeout(fn, 0) が0msにならない本当の理由
「setTimeout の最小遅延は4ms」という説明は広く流布しています。仕様の該当ステップです。
4. If timeout is less than 0, then set timeout to 0.5. If nestingLevel is greater than 5, and timeout is less than 4, then set timeout to 4.
条件が2つ付いています。「入れ子レベルが5を超え」かつ「指定値が4未満」。一律の最小遅延ではありません。散文側も同じことを言っています。
Timers can be nested; after five such nested timers, however, the interval is forced to be at least four milliseconds.
入れ子レベルは、setTimeout が作ったタスクの中からさらに setTimeout を呼ぶ重なりの回数で、setInterval も同じカウンタを共有します。
では、入れ子でない最初の setTimeout(fn, 0) はなぜ0msで動かないのか。理由はクランプではありません。満了時に起きるのは即時実行ではなくこれです。
Let completionStep be an algorithm step which queues a global task on the timer task source given global to run task.
タスクとして積まれるのです。実行されるのは、イベントループが次にそのタスクを選んだとき。つまり同期コードが終わり、マイクロタスクが片付いた後です。仕様自身も釘を刺しています。
This API does not guarantee that timers will run exactly on schedule. Delays due to CPU load, other tasks, etc, are to be expected.
「`setTimeout(fn, 0)` は仕様で最小4msにクランプされるので0msにならない」をHTML仕様に照らすとどう評価できますか。
task queue という名前
queue と名付けられているので待ち行列に見えますが、仕様の定義は set です。取り出すのも先頭ではなく「最初の runnable なもの」。仕様は名前と定義がずれることを承知のうえで、理由を添えて set と定めています。
名前からの推測 仕様の規定先入れ先出しで取り出す 最初の runnable なタスクを取るデータ構造は queue データ構造は setmicrotask queue も同類 "The microtask queue is not a task queue."
Promise の「マイクロタスク」という帰属
Promise は JavaScript の機能なので、マイクロタスクという扱いも ECMAScript が決めていそうに見えます。しかし ECMAScript は "Job" としか言わず、マイクロタスクキューに入れると決めているのは HTML のほうです。機能の出身地と、挙動を決めている仕様が違います。
仕様 使う語 決めていることECMAScript §9.5 Job 順序と「1つずつ完走」だけHTML §8.1.6.6.4 microtask "HTML schedules these operationsin the microtask queue."
「task queue は実は set」と「Promise がマイクロタスクなのは HTML の規定」。この2つに共通する、間違いの起き方の構造は何でしょうか。
どちらも、確かめるべき場所がひとつ隣にあります。名前の見た目、あるいは機能の出身地から推測すると、その隣を読まずに済ませてしまいます。
この章のまとめ
- イベントループの仕様上の役割は「イベント・ユーザー操作・スクリプト・レンダリング・ネットワークを協調させる」こと。JSを回すだけの仕組みではない。
- task queue は set。理由も仕様に明記されている(先頭ではなく最初の runnable なタスクを取るから)。microtask queue は本物の queue。
- 仕様は "The microtask queue is not a task queue." と明言している。同類ではない。
- 処理モデルは タスク1つ → マイクロタスク全部。マイクロタスク側は "While ... is not empty" で、実行中に積まれた分も同じループで処理される。
setTimeout(fn, 0)の4msクランプは 入れ子5超かつ4未満のときだけ。0msにならない主因は タスクとして積まれて順番待ちをするから。- Promise がマイクロタスクなのは HTML の規定。ECMAScript は "Job" としか言わない。
- 「1イベントループ = 1スレッド」は仕様の規定ではない("do not necessarily correspond to implementation threads")。
自分の現場で確かめる
読んだだけでは身につきません。手元の環境で実際に見てみてください。
理解度チェック
読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。
HTML仕様は microtask queue と task queue の関係をどう規定していますか。
用語集(6語)
- イベントループ
- 仕様の定義は「イベント・ユーザー操作・スクリプト・レンダリング・ネットワークなどを協調させる(coordinate)ための仕組み」。JavaScriptを実行するだけの仕組みではない。
- task queue
- 仕様上は **set(集合)**。名前に queue と付くが、取り出すのは先頭ではなく「最初の *実行可能な(runnable)* タスク」。どれを選ぶかは implementation-defined。
- microtask queue
- 本物の **queue**。仕様は "The microtask queue is not a task queue." と明記する。取り出しは dequeuing で、チェックポイントでは空になるまで処理される。
- task source
- タスクの出どころを表す分類。タイマーなら timer task source、描画なら rendering task source。同一タスクソース内の順序は崩されない。
- microtask checkpoint
- タスクを1つ実行し終えた直後に行われる処理。マイクロタスクキューが空になるまで実行する。再入を防ぐフラグを持つ。
- rendering opportunity
- その navigable の内容をユーザーに提示できる状態。仕様は選び方を規定していない。描画はこの機会があるときだけ。