タスクキュー

タスクキュー (Web)

[2] タスクキュー (task queue) は、イベントループにおけるタスク順序付きリスト (キュー) です。 Webブラウザー内に常にいくつか存在します。

仕様書

意味

[4] タスクキューは、タスクキューです >>1。 0個以上のタスクを入れたり出したりできます。 キューですから原則として FIFO ですが、それ以外の特別な操作もあります。

[5] 一つのタスクが複数のタスクキューに同時に含まれることはありません。

文脈

[18] イベントループは、1つ以上タスクキュー群を持ちます >>1

[31] イベントループがいくつタスクキューを持つかは、実装依存です。

[12] 例えば、マウス操作その他の利用者の操作 (利用者対話タスク源) のタスクキューと、それ以外のタスクキューとで2つ用意し、 利用者の操作のタスクキューを優先的に処理する、という戦略を採ることができます。 >>1

[32] あるイベントループで、 あるタスク源から来たタスクをどのタスクキューに追加するかは、 実装依存の方法で固定しなければなりません >>1 (>>3)。

[84] 実装戦略によっては実行時にタスクキューが増減するかもしれませんが、 同じタスク源タスクは同じタスクキューに入れなければならないという原則は歪められません。


[76] サービスワーカー登録は、1つ以上タスクキュー群 (task queues) を持ちます。 これは活性ワーカーが動作していない間にタスクを保持しておくもので、 これ自体を使ってタスクを実行するものではありません。 >>75

タスク源

[46]タスクは、何らかのタスク源 (task source) から来る (come) ものと定義されます >>44

[61] タスクキュータスク源によって分けられており、 同じタスク源タスク同士の実行順序はタスクキューへの追加順序となることが保証されます。

[62] タスク源は、追加時にタスクキューの決定に使われる他、 何らかの理由でタスクキューからタスクを削除する条件として使われることもあります。

[49] タスク源としては次のものがあります。

[53] タスク源の一覧は >>54 にあります。

[50] ほとんどのタスク源イベントループに1つずつ存在していますが、 ポートメッセージキュー著者MessagePort オブジェクトを作成することによって任意個作成されます。 クライアントメッセージキューServiceWorkerContainer オブジェクトの数だけ存在します。 媒体要素イベントタスク源XMLHttpRequestタスク源 もオブジェクトごとに存在します。 FileReaderタスク源FileSaverタスク源もオブジェクトごとに存在するようです。

[51] 未出荷済みポートメッセージキュー仮想 (virtual) タスク源 >>54 であり、そのタスクポートメッセージキューにも未出荷済みポートメッセージキューにも属するという特殊な状態になっています。 未出荷済みポートメッセージキューイベントループごとに1つだけあります >>45

[52] 転送していない MessagePort では必ず同じ順序でタスクが実行されることを保証し、 転送してしまった MessagePort では任意の実行順序となることを認めるためにこのような複雑な構造になっています。
[88] 同じタスク源なら同じタスクキューを使うとの制約から、 未出荷済みポートメッセージキューに入るタスクは (ポートメッセージキューに関わらず) 同じタスクキューに入るものとしなければなりません。出荷済みのポートメッセージキューにはこの制約はありません。

マイクロタスクとの関係

[58] マイクロタスクタスク源はすべてマイクロタスクタスク源と定義されています。

[59] マイクロタスクにはタスクキューとは別のマイクロタスクキューが存在しています。 これはマイクロタスク源タスク (マイクロタスク) を実行するタスクキューとは別のものです。

タスクキューの構造

[83] 仕様書上、タスクキュータスク順序付きリストであるとしか説明されていません。 しかし、タスクキュー上のタスクには、タスク源文書fetch という情報が関連付けられていて、これがタスクキューが関わる色々な演算で重要な役目を持ちます。

[85] タスクキューは、タスク源文書fetch という情報を持ったタスクキューであるが、 通常のキューとは異なる特殊な演算も持つ、と解釈することもできますし、 タスク源文書fetch をキーとするタスクのリスト (タスクキュー部分リスト) をいくつか重ね合わせて全体として順序を持つリストとして捉えたものがタスクキューである、 と解釈することもできそうです。

[86] ポートメッセージキュークライアントメッセージキューは、タスクキュー部分リストの一種であると解せます。

[87] 未出荷済みポートメッセージキューは、いくつかのポートメッセージキューを束ねたものと捉えることができます。 ただし、未出荷済みポートメッセージキュータスクと各ポートメッセージキュータスクが異なるタスクキューを利用する場合を考えると、 事情は若干複雑化します。

[65] タスクキュー部分リストは、状態を持ちます (>>66)。

追加

[11] 仕様書アルゴリズム上で新たなタスクの実行を予約する操作を、 タスクをキューに追加 (queue a task) >>1 といいます。

[43] タスクは、その処理に関係するイベントループに追加されます。 Webブラウザーが複数のイベントループを持つ場合、 処理対象の文書ワーカーを担当しているイベントループタスクキューに追加されることになります。

[3] タスクは、その出自であるタスク源によって決まるタスクキューに追加されます。 イベントループが複数のタスクキューを持つ場合、 同じタスク源からのタスクは必ず同じタスクキューに追加され、 相互の順序は保持されますが、 異なるタスク源からのタスクは異なるタスクキューに追加されるかもしれないため、 順序は保証されません。

[37] タスクをキューに追加する処理は、次の引数を受け取ります。

イベントループ
タスクをキューに追加する処理を現に実行しているイベントループ
処理
アルゴリズムと一連の引数の値。
タスク源
タスク源
文脈
要素閲覧文脈環境設定群オブジェクトのいずれか。 あるいはスクリプトが指定された場合、その設定群オブジェクト >>1タスクをキューに追加の呼び出し元を意味しています。 (クライアントメッセージキューの場合は、クライアントメッセージキュー関連設定群オブジェクト >>94。)
fetch
fetch または nullfetch からタスクをキューに追加する場合には、 その fetch実現値となります。既定値は null
捨てる処理
handle fetchInstall で指定されます。

[38] 次のようにしなければなりません

  1. [14] 文脈環境設定群オブジェクトで、 文脈大域オブジェクトWorkerGlobalScope で、 文脈大域オブジェクト閉じ中なら、
    1. [68] ここで停止します。 >>10
  2. [42] 文書を、文脈により、次の値に設定します >>1
    要素
    文脈節点文書
    閲覧文脈
    文脈活性文書
    設定群オブジェクト
    文脈有責文書
  3. [39] タスクを、タスクに設定します。
    [40] タスク
    処理
    処理
    triggered by user activation その他のフラグ群
    イベントループ現在走っているタスクnull でなければ、 イベントループ現在走っているタスクtriggered by user activation その他のフラグ群
    タスク源
    タスク源
    文書
    文書
    fetch
    fetch
    順序
    イベントループ内でタスクをキューに追加の実行順序を表す値
    捨てる処理
    捨てる処理
  4. [13] タスクキューを、 イベントループタスクキュー群タスクキューのいずれかをタスク源に基づき選択した結果に設定します。 選択方法は実装依存ですが、基準タスク源から一意に定まるものでなければなりません。
  5. [41] タスクタスクキューの末尾に追加します。

[35] タスクをキューに追加する操作は、色々な処理から呼び出されます。

[92] 移動の項も参照。

存在

[28] EventSource, MessagePortごみ収集のタイミングは、 タスクタスク・キューに残っているかによって決まります。

[29] これはタスクから EventSource, MessagePort強い参照があると解釈できるかもしれません。
[30] XHR は逆にごみ収集によってタスクを破棄します。

[8] the embed element setup steps は、 同要素に関するタスクが他に追加されている場合、何も実行しません。 (実行中かどうかではなく追加されたかどうかの検査です。) この検査は自タスクのみならず、そこから追加された他のタスクキューからも行われます。

取得

[15] タスクキューFIFO っぽいもので、基本的には最古のものから取得 (実行)、 削除されます。しかし条件を満たさないタスクイベントループに無視されることになっていますから、 厳密には FIFO とは言えません。

[20] イベントループについてタスクキューからタスクを選択するには、 次のようにしなければなりません

  1. [70] タスクキューを、 イベントループタスクキュー群タスクキューのいずれかをタスク源に基づく実装依存の方法で選択した結果に設定します。 >>9
  2. [72] リスト群を、タスクキュータスクキュー部分リストのうち、 空でなく、状態が無効ではないものの集合に設定します。
  3. [64] リスト群が空なら、
    1. [89] null を返します。
  4. [91] それ以外なら、
    1. [90] リスト群に含まれるリストに含まれるタスク順序が最も若い (古い) ものを返します。

[21] 同じタスクキュータスクは、無視 (遅延) されるものを除き、 実行順序が保証されています。異なるタスクキュータスク同士がどの順序で実行されるかは、 実装依存です。

[69] この辺の処理は、プラットフォームの影響を受けることもあるでしょうし、 あるいは何を優先的に実行するかは実装の品質の問題であって (>>12) Webブラウザー事業者が工夫して競合するべき点でもあるでしょうから、 仕様としてはあまり具体的に規定せず、かなり自由度を持たせているようです。 何をどのような順序で処理するかが相互運用性にあまり影響しないということもあります。

[79] WebSocketメッセージ受信におけるタスクの実行では、 タスクの実行に必要な I/O 処理を待つ間他のタスクキューを実行するような効率化が推奨されています。

[48] なお、タスクイベントループによる実行後にタスクキューから削除されます。


[66] タスクキュー部分リストは、状態を持ちます。その値は有効か無効のいずれかです。 既定値は有効です。

[67] 文書null でなく、文書完全に活性でない >>9 ようなタスクキュー部分リスト状態は、無効とします。

[47] 従って、履歴移動により非表示状態になった文書タスクは、 実行されません。しかし捨てられたわけではないので、再び表示状態に戻れば実行されます。

[34] ポートメッセージキュークライアントメッセージキューは、 有効か無効かのいずれかの状態を持ちます。 既定値は無効です。


[80] HTML構文解析器script 要素終了タグの処理は、 字句化器をブロック (block the tokenizer) する場合があります。これは、 字句化器をブロック解除 (unblock the tokenizer) するまでの間、 当該字句化器を実行することになるタスクイベントループが実行しないものと説明されています >>78

[71] なぜかこれは構文解析器の動作の規定で説明されるだけで、 イベントループ側のアルゴリズムには組み込まれていません。 そのため仕様書の意図する正確な動作は不明です。 しかし、構文解析器自体が正常に動作することや他の挙動との整合性、 実際の Webブラウザーの動作との一貫性を考慮すると、 イベントループが単一のタスクキューしか持たない場合であってもそのようなタスクの後に続く一切のタスクを実行できないとは考えにくく、 完全に活性でないタスクと同様、ブロック解除されるまで無効とされると解釈するのが妥当そうです。

[82] なお、このような挙動を引き起こしたHTML構文解析器によってブロックされる、 字句化器を実行することになるタスク、というのは、 navigate によって実行される fetchprocess responseprocess response end-of-body の処理を行うネットワークタスク源タスクです。

[81] ということは、字句化器をブロックするとは、 (タスク源 = ネットワークタスク源, 文書 = HTML構文解析器文書, fetch = その構文解析器と対になる fetch) のタスクキュー部分リスト状態無効に設定する、と言い換えられることになります。

削除

[22] タスクは実行される際にキューから削除されますが、それ以外にも削除されることがあります。

移動

ポートメッセージキュー

[17] ポートメッセージキューにおいては、 タスクが他のポートメッセージキューへと移動されることがあります。 タスクキュー部分リスト内のすべてのタスクを削除し、 他のポートメッセージキューに改めて追加するものと解することができます。

[36] ポートメッセージキューの操作 (postMessageTransfer) でタスクポートメッセージキューに追加されることがあります。 仕様書上はタスクをキューに追加を使わずに規定されていますが、 ポートメッセージキュータスクキュー部分リストであると考えれば、 タスクをキューに追加する操作で記述できます。

[73] ポート出荷に伴うタスク移動: ポートメッセージキュータスクは、MessagePort既に出荷済みフラグがである間、 未出荷済みポートメッセージキューに属するものとみなされ、 ポートメッセージキューとしての処理は停止されると規定されています。 これは (色々な実装方法がありそうですが) 未出荷済みポートメッセージキューを収容するタスクキューからポートメッセージキューに相当するタスクキュー部分リストを削除し、 ポートメッセージキューが本来収容されるべきタスクキューに追加する操作と解することができます。 この操作ではタスク自体は削除と移動されるわけではなく、 タスクキュー上のタスク順序が維持される必要があります。

サービスワーカー

[93] サービスワーカーを走らせる処理、 サービスワーカーを終端させる処理で、 イベントループサービスワーカー登録との間でタスクが移動されることがあります。

[77] handle fetchタスクが捨てられる時は、 タスク捨てる処理が実行されます。

イベント順との関係

[55] DOM3イベントイベント同士の関係をイベント順により規定しています。 DOM3イベントイベント・ループタスクという概念を使っておらず、 このイベント順は適宜タスク源として使うことによってイベント・ループと互換性がある形で実装できる、 としています。

[57] 具体的にどう対応付けるのかは説明を読んでもあんまりよくわかりません。 HTMLマウス鍵盤も同じ利用者対話タスク源で扱っていますが、 DOM3イベントは独立してるからそれぞれ別のタスク源だ、とか言っていますし、 焦点の変更など独立した操作がそれぞれタスク源だ、とか訳のわからないことも言ってます。

ごみ収集との関係

[74] ごみ収集ポートメッセージキュー参照。

歴史

[95] Clarify realm and task-queuing situation in pipeTo() by domenic · Pull Request #902 · whatwg/streams () <https://github.com/whatwg/streams/pull/902>

[96] Add self.queueMicrotask() (domenic著, ) <https://github.com/whatwg/html/commit/9d7cf125f960e6bb8d9b7c9456595f505f2e9d4b>