ポートメッセージキュー

MessagePort インターフェイス (DOM)

仕様書

作成

[36] MessagePort インターフェイスコンストラクターを持ちません。

[37] 作成するには、 MessageChannel オブジェクトなどを作成する必要があります。


[39] 環境設定群オブジェクト所有者に関する新しいMessagePortオブジェクトの作成 (create a new MessagePort object) は、 次のようにしなければなりません

  1. [41] ポートを、新しい MessagePort に設定します >>32
    [42] MessagePort
    所有者
    所有者
  2. [128] (イベントループタスクキュー群のいずれかのタスクキューにおいて、 ポートポートメッセージキュータスクキュー部分リストの1つとなります。)
  3. [127] ポートを返します >>32

[40] この処理は、次の場面から呼び出されます。

文脈

[33] MessagePort インターフェイスは、 文書環境ワーカー環境AudioWorklet晒されています >>32

[96] MessageChannel オブジェクトを作成すると、 port1port2 の2つの IDL属性から MessagePort にアクセスできます。

[98] postMessage メソッドで送信する MessagePort を指定できます。

[97] postMessage の受信やワーカーの作成で MessageEvent イベント発火された時は、 ports IDL属性MessagePort配列にアクセスできます。

[100] ワーカーは、暗示的ポートとして MessagePort を持ちます。

[101] SharedWorker オブジェクトは、 port IDL属性MessagePort を持ちます。


[99] WorkerGlobalScope は、 ワーカーのポート群 (the worker's ports) として MessagePort のリストを保持しています >>149

ワーカー内で作成されたポートが自動的に追加されます。暗示的なポートも含まれます。

[170] protected worker かどうかの判定で参照されます。

[171] ワーカーを走らせる処理の最後の片付けの段階で disentangle の実行のため参照されます。

[150] 同様に Windowポート群を持つと考えられます (>>107)。

状態

[38] EventTarget としての状態に加えて、 次の状態を持ちます。

entangle されたポート >>32
他の MessagePort オブジェクト>>107 も参照。
ポートメッセージキュー
タスク源タスクキュー部分リストと捉えることもできます。 初期状態は空です。 有効無効かのいずれかの状態を持ち、その初期状態は無効です。
既に出荷済みフラグ
ブール型。 初期状態は
所有者 (owner)
環境設定群オブジェクト>>32

メンバー

[34] EventTarget継承しています >>32

[35] 加えて、次のメンバーがあります。

ポートメッセージキュー

[135] MessagePort オブジェクトは、 ポートメッセージキュー (port message queue) を持ちます。 初期状態は空です。 >>65

[136] MessagePort オブジェクトポートメッセージキューは、 無効 (disabled) または有効 (enabled) のいずれかの状態にあります。 初期状態は無効です。一旦これを有効にすると、無効には戻せません。 >>65

[137] MessagePort オブジェクトは、 既に出荷済み (has been shipped) フラグを持ちます。 初期状態はです。 >>32

[142] 未出荷済み

[64] 2つの状態が、 postMessage の結果生じる message イベントの実行タイミングに影響します。 仕様書の規定は複雑でわかりにくいですが:

... 整理してみると単純な話で、キューの状態が有効なら実行され、 出荷済みならポートメッセージキュー扱い、 未出荷なら未出荷済みポートメッセージキュー扱いになる、ということです。


[143] ポートメッセージキュー未出荷済みポートメッセージキューは、 タスクキューであるにも関わらず、タスク源である >>32 と規定されています。それでいて、イベントループによって (実行されるべきタスクのリストとして) 使われる >>32 ともされていて、 イベントループの持つタスクキューの一種であるかのようにも捉えられます。

[144] 仕様書の履歴を辿ってみると、元はポートメッセージキューはその名の通り message イベントキューでした。 このキューに追加されたイベントは、(準備が整い次第) イベント発火するタスクイベントループタスクキューに追加され、 ポートメッセージキューからは削除されることになっていました。

[145] これがその後の改訂 >>133 で、ポートメッセージキュー自体がタスクキューになりました。 コミットメッセージMessagePort が他のイベントループに渡った時にイベントが失われないための変更だと説明されており、 MessagePortTransferイベントを新イベントループ下に移動させることが狙いだったようです。

[146] この変更で、ポートメッセージキュータスク源であるということになりました。 仕様書は「タスクタスク源から来る」としか言っておらず、 タスク源とは何なのか (ラベルなのかリストなのか) はよくわかりませんが、 (実装でどう扱うかは別として、仕様書の裏の考え方としては) タスク源とはそれ自体がタスクリスト (タスクキュー部分リスト) で、 そのようなリストをいくつか束ねたものがタスクキューだ、 といえるのかもしれません。


[63] クライアントメッセージキューと似ています。

処理

entangle

[43] 2つの MessagePort を関連付けた状態とすることを entangle といいます。 ポート1ポート2entangle は、次のようにしなければなりません

  1. [44] ポート1entangle されたポートnull でなければ、
    1. [45] ポート1disentangle を実行します。 >>32
  2. [46] ポート2entangle されたポートnull でなければ、
    1. [47] ポート2disentangle を実行します。 >>32
  3. [48] ポート1entangle されたポートを、ポート2に設定します。 >>32
  4. [49] ポート2entangle されたポートを、ポート1に設定します。 >>32
  5. [151] ポート1所有者ポート2所有者が異なるなら、 (>>107)
    1. [152] ポート1所有者大域オブジェクトポート群に、 ポート1を追加します。
    2. [153] ポート2所有者大域オブジェクトポート群に、 ポート2を追加します。

[51] entangle は、次の場面で呼び出されます。

[50] この処理が済んだ状態を、ポート1ポート2entangle されている (entangled) といいます >>32

[102] entangle 状態を解除することを、 disentangle >>32 といいます。 MessagePort ポートdisentangle は、 次のようにしなければなりません。

  1. [103] ポートentangle されたポートentangle されたポートを、 null に設定します。
  2. [155] ポートentangle されたポート所有者大域オブジェクトポート群から、 ポートentangle されたポートを (あれば) 削除します (>>107)。
  3. [104] ポートentangle されたポートを、 null に設定します。
  4. [154] ポート所有者大域オブジェクトポート群から、 ポートを (あれば) 削除します (>>107)。

[105] disentangle は、次の場面で呼び出されます。

[106] entangle の中から disentangle が呼び出される、つまり entangle 関係が書き換えられて他の MessagePort と関連付けられた状態になるのは、 Transfer からの呼び出しの場合のみです。すなわち postMessage により MessagePort が送られて、他方の MessagePort の接続先が新しい方に差し替えられる場合です。 これ以外で disentangle された MessagePort は、二度と entangle されることはありません。

transfer

[52] MessagePort オブジェクトは、 transferable object です。 >>32

[53] MessagePort オブジェクトtransfer steps は、データ保持子について、 次のようにしなければなりません >>32

  1. [54] 出荷します。
  2. [165] データ保持子PortMessageQueue を、 ポートメッセージキューに設定します。
  3. [58] 遠隔ポートを、 文脈オブジェクトentangle されたポートに設定します。
  4. [59] 遠隔ポートnull 以外なら、
    1. [60] 遠隔ポート出荷します。
    2. [166] データ保持子RemotePort を、遠隔ポートに設定します。
  5. [167] それ以外の場合、
    1. [168] データ保持子RemotePort を、 null に設定します。

[169] transfer-receiving steps は、データ保持子について、 次のようにします >>32

  1. [84] 出荷します。
  2. [55] 所有子を、 関連設定群オブジェクトに設定します。
  3. [57] データ保持子PortMessageQueue が空でなければ、繰り返し、
    1. [123] タスクを、 データ保持子PortMessageQueuedequeue した結果に設定します。
    2. [124] タスクに transfer (>>126) します。
  4. [56] データ保持子RemotePortnull 以外なら、
    1. [61] データ保持子RemotePortentangle します。

[126] 旧タスク新ポートへの transfer は、 次のようにしなければなりません

  1. [138] タスクをキューに追加します。
    イベントループ
    新ポート所有者有責イベントループ
    処理
    引数付きのアルゴリズム
    変数
    最終対象ポート
    新ポート >>92
    処理
    旧タスク処理処理
    タスク源
    新ポートポートメッセージキュー >>32
    文脈
    新ポート所有者 >>32

[140] 仕様書ではタスクをキューに追加する操作を使わずに記述されています。

ポートの状態の変更

[67] MessagePort ポートポートメッセージキューの有効化は、 次のようにしなければなりません >>32

  1. [70] ポートポートメッセージキュー状態を、有効に設定します。

[68] これによって、それまでイベントループタスクキューの処理で無視されていた本ポートメッセージキュータスクが、処理対象にと変化します。

[91] 次の場面で呼び出されます。


[85] MessagePort ポート出荷は、 次のようにしなければなりません >>32

  1. [86] ポート既に出荷済みフラグを、に設定します。
  2. [69] ポートについてポート出荷に伴うタスク移動を行います。

[87] HTML Standard では、これは Transfer (>>53) から実行される処理となっています。 意味的には、それ以外にワーカーを走らせる処理、 new Workernew SharedWorker からも実行されるべきではないかとも思われますが、 そうは規定されていません。歴史的経緯による誤りなのか、意図通りなのかははっきりしません。 現実問題どれだけその差が観測できるかは微妙なところかもしれません。

それぞれの項も参照。

ポートメッセージキューの操作

[71] 処理MessagePort ポートポートメッセージキューに追加するには、 次のようにしなければなりません

  1. [138] タスクをキューに追加します。
    イベントループ
    ポート所有者有責イベントループ
    処理
    引数付きのアルゴリズム
    変数
    対象Realm
    ポート関連Realm >>92
    処理
    処理
    タスク源
    ポートポートメッセージキュー >>92
    文脈
    ポート所有者 >>92
[147] 仕様書ではタスクをキューに追加する操作を使わずに記述されています。

[129] これは postMessage から呼び出されます。

ごみ収集

[107] MessagePort ポートentangle されているなら、 次のいずれかとしなければなりません >>108

[120] 実装上、 entangle されているポート同士が異なるプロセスで動作しているなど、 直接強い参照を保持しているとすると実現困難な場合があるため、 2つの方法が認められているものと思われます。2つの方法は完全に等価なわけではありませんが、 著者スクリプトから直接観測可能な挙動としては同一です。

[139] ワーカーに関しては、 WorkerGlobalScopeワーカーのポート群として当該ワーカー外に entangle されたすべての MessagePort のリストを大域オブジェクトが保持することになっています。 これは事実上 >>119 を求めるものです (他の等価な実装方法も理論上はあり得ますが...)。 文書環境に関しても、同様に MessagePort のリストを保持するのが現実的でしょう。

[157] 実装上は、 disentangle されないまま両端ともスクリプトから参照されなくなった時に、 ポート群から除去されてこれらがごみ収集されるよう、注意が必要です。

[148] 同じ環境内のポート同士は、 >>118 の方法を採っても、 >>119 の方法に準ずることにしても良さそうです。

[121] MessagePortごみ収集されないということは、 そこに登録されたイベントリスナーごみ収集されないということです。 つまりこの要件は、イベントリスナーを登録した後に MessagePort への参照が破棄されたとしても、相手方のポートが生きている限りはイベントリスナーが呼び出される可能性を維持するためのものです。

[122] もちろん、両側の MessagePort が共に参照されない状態になった場合は、 もうイベントリスナーが呼び出される可能性はありませんから、両方共に破棄できます >>108

[109] 未実行のタスクMessagePortごみ収集の関係として、 次のように規定されています。

[115] このうち >>113 は通常のタスクであれば当然にタスクからイベント対象への強い参照が維持されているはずと考えられるところ、 message については実行時点で含まれるポートメッセージキューMessagePortイベント対象とする (>>71) との変則的な規定があるための条件なのでしょうか。

[116] >>114 は、逆に言えばポートメッセージキューが無効の場合は実行されずに捨てられる (かもしれない) し、空になったら捨てられる (かもしれない) ということです。

[117] >>113>>114 に含まれるようにも読めますが、イベントループタスクを実行しようとしてポートメッセージキューから取り出した瞬間に空になって MessagePort が破棄されないために >>113 が必要なのでしょうか。 と思いましたがタスクは実行が終わるまでタスクキューに残ったままですよね...

[131] >>113タスクキュータスクが入っていれば、という規定になっていて、 ポートメッセージキューとは言っていません。ポートメッセージキュータスク源であるとはされていますが、 タスクキューとはされていません (いかにもタスクキューっぽい名前ですが)。 従ってポートメッセージキューが無効なら、 >>113 の条件には合致しないものと思われます。 (無効のまま MessagePort が破棄されたなら、有効化する手段がなくなるので、 捨てても捨てなくても観測できません。)

[156] 現実には MessagePort が無効のまま破棄された時、 タスクキュー内にポートメッセージキュータスク (がイベント対象として保持している MessagePort 自身への参照) もごみ収集されるよう、注意する必要があります。

MessageChannel インターフェイス port1 属性、 port2 属性

[27] MessageChannel インターフェイスport1 IDL属性port2 IDL属性 >>26 は、それぞれ文脈オブジェクトポート1ポート2を返します。

[28] MessageChannel オブジェクトポート1ポート2は、 コンストラクターによって新たに作成された MessagePort オブジェクトがそれぞれに設定されます。これらの値は変化することはありません。

[29] 2つのポートは、作成された時点では (異なるオブジェクトであることを除けば) まったく同じ初期状態です。どちらをどう使うかは、著者が決めることができます。

[30] 例えば port1 の側を postMessage で通信の相手先に渡したら、 以後のこちら側の送受信には port2 を使うことになります。 逆に port2 を渡したら、 port1 を使うことになります。

MessagePort インターフェイス start メソッド

[88] MessagePort インターフェイスstart メソッドは、次のようにしなければなりません >>32

  1. [89] 文脈オブジェクトポートメッセージキューの状態無効なら、
    1. [90] 文脈オブジェクトポートメッセージキューの有効化を実行します。

MessagePort インターフェイス close メソッド

[93] MessagePort インターフェイスclose メソッドは、次のようにしなければなりません >>32

  1. [179] 文脈オブジェクトDetached を、に設定します。
  2. [94] 文脈オブジェクトentangle されたポートnull 以外なら、
    1. [95] 文脈オブジェクトdisentangle を実行します。

[112] MessagePort が不要になったら、明示的に閉じて disentangle することが強く勧められています (strongly encouraged) 。 明示的に閉じずないと必ずしも即座にごみ収集されるとは限らないため (>>107)、 メモリーを無駄にすることとなります。 >>108

MessageEvent インターフェイス ports 属性

[162] MessageEvent インターフェイスMessageEventInit 辞書ports IDL属性/辞書メンバー >>161 は、 受信した MessagePort配列を表します。

[163] 値は MessagePortsequence です >>12辞書での既定値は配列です >>12

歴史

[73] ポートメッセージキューはここで導入されました。 open と closed の2つの状態を持っていました。 この時同時に追加された start メソッドを呼び出すか、 onmessage IDL属性に値を設定するかのいずれかにより、 closed から open へと遷移することとされていました。

[134] これまで投稿済みメッセージタスク源が使われていましたが、 >>133 により、使われなくなりました。

[1] IRC logs: freenode / #whatwg / 20130604 ( ( 版)) http://krijnhoetmer.nl/irc-logs/whatwg/20130604

[2] [whatwg] onclose events for MessagePort ( ( 版)) http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2013-October/041298.html

[3] Web Applications 1.0 r8306 People apparently don't like it when the spec requires things that are impossible to implement, go figure. (In this case, synchronously detecting that one of the MessagePorts being Transferred in the MessagePort message is actually the target of the message. You can't necessarily know this synchronously, since if the port has been shunted around between workers, you might only discover who the final target actually is after the message has itself bounced between threads for a while.) ( ( 版)) http://html5.org/tools/web-apps-tracker?from=8305&to=8306

[4] [whatwg] onclose events for MessagePort ( ( 版)) http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2013-December/041739.html

[5] Web Applications 1.0 r8336 Add a way to catch the other side of a port having a catastrophic death. ( ( 版)) http://html5.org/tools/web-apps-tracker?from=8335&to=8336

[6] Web Applications 1.0 r8341 Updates for r8297, fixing <option> to treat 'dirtiness' correctly, and r8336, fixing 'error' events sent to MessagePort objects to not race messages sent from those ports (or, worse, the event that the port is delivered on...). ( ( 版)) http://html5.org/tools/web-apps-tracker?from=8340&to=8341

[7] IRC logs: freenode / #whatwg / 20131218 ( ( 版)) http://krijnhoetmer.nl/irc-logs/whatwg/20131218

[8] Web Applications 1.0 r8342 Make sure subsequent owners of an ill-fated port's friend can know about that fate ( ( 版)) http://html5.org/tools/web-apps-tracker?from=8341&to=8342

[9] [whatwg] onclose events for MessagePort ( ( 版)) http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2014-January/041953.html

[10] Web Applications 1.0 r2020 Make MessagePort objects not be owned by Windows necessarily, and remove ownerWindow. ( ( 版)) https://html5.org/r/2020

[11] Web Applications 1.0 r2116 Change 'unload' to 'close' for MessagePorts. ( ( 版)) https://html5.org/r/2116

[12] Web Applications 1.0 r2531 Simplify the way messages in ports are handled when the destination's document is not available. ( ( 版)) https://html5.org/r/2531

[13] Web Applications 1.0 r2032 Remove redundant event listeners on MessagePort. ( ( 版)) https://html5.org/r/2032

[14] Web Applications 1.0 r2031 MessagePort should implement EventTarget. ( ( 版)) https://html5.org/r/2031

[15] Web Applications 1.0 r3346 Allow cloning and posting of closed ports. (credit: dw) ( ( 版)) https://html5.org/r/3346

[16] Web Applications 1.0 r2885 postMessage() methods that take MessagePort objects now take MessagePortArray objects. ( ( 版)) https://html5.org/r/2885

[17] Web Applications 1.0 r2024 Simplify garbage collection for ports even further. Define dicarding of Document objects better for ports. Prevent inactive documents from receiving messages. ( ( 版)) https://html5.org/r/2024

[18] Web Applications 1.0 r3227 Fix the garbage collection rules for ports to actually make sense, and add a note for authors urging them not to rely on the gc for ports. ( ( 版)) https://html5.org/r/3227

[19] Web Applications 1.0 r3147 Clarify MessagePort GC rules. ( ( 版)) https://html5.org/r/3147

[20] Web Applications 1.0 r2358 MessagePorts shouldn't be GCed even when their queue is closed if they have events targetted at them. (credit: ap) ( ( 版)) https://html5.org/r/2358

[21] Web Applications 1.0 r2023 Simplify message ports: use queueing instead of transient 'active' functionality. Also, make localStorage use the same mechanism for obtaining origin as openDatabase(). ( ( 版)) https://html5.org/r/2023

[22] Web Applications 1.0 r2357 Define MessagePort such that they won't be garbage collected while a message is outstanding. (credit: ap) ( ( 版)) https://html5.org/r/2357

[23] Add <script type="module"> and module resolution/fetching/evaluation · whatwg/html@cd1a9fb ( 版) https://github.com/whatwg/html/commit/cd1a9fb1e83f7d0bc30be8b34ecdaf444a0b19a4

[24] Write structured clone algorithm in terms of ECMAScript · whatwg/html@bfb960c ( 版) https://github.com/whatwg/html/commit/bfb960c938580c95e77365e614218b952f96375b

[25] Use FrozenArray for Navigator#languages and MessageEvent#ports · whatwg/html@e4df68a ( 版) https://github.com/whatwg/html/commit/e4df68a41b86753c7fcdd0d8ea4615f63ffc87e9

[158] 28813 – There's no way to tell when a MessagePort is closed. () https://www.w3.org/Bugs/Public/show_bug.cgi?id=28813

[159] Use FrozenArray for Navigator#languages and MessageEvent#ports · whatwg/html@e4df68a ( 版) https://github.com/whatwg/html/commit/e4df68a41b86753c7fcdd0d8ea4615f63ffc87e9

[160] Make MessageEvent's ports attribute non-nullable (cdumez著, ) https://github.com/whatwg/html/commit/df2c0c448612d5b8ab85ad3c6ce0255ee11c0b01

[164] Breaking: refactor structured clone into serialize/deserialize (domenic著, ) https://github.com/whatwg/html/commit/97d644c97335956610a31e8ad98d1a388c063e84

[62] Breaking: refactor structured clone into serialize/deserialize (domenic著, ) https://github.com/whatwg/html/commit/97d644c97335956610a31e8ad98d1a388c063e84

[141] Editorial: restructure ownership of workers to parent-owners (annevk著, ) https://github.com/whatwg/html/commit/59a4750f475acd789ee436b4906972ba2081d8b3

[172] Editorial: restructure ownership of workers to parent-owners (annevk著, ) https://github.com/whatwg/html/commit/59a4750f475acd789ee436b4906972ba2081d8b3

[173] Meta: remove "ILLFATED" MessagePort design (annevk著, ) https://github.com/whatwg/html/commit/1208d255eddebe7efc3bba59bc297709e3b30660

[174] Introduce MessagePort on AudioWorkletNode/Processor by hoch · Pull Request #1233 · WebAudio/web-audio-api () https://github.com/WebAudio/web-audio-api/pull/1233

[175] Expose MessagePort to AudioWorklet (hoch著, ) https://github.com/whatwg/html/commit/458347c0d677dbd6e2414d6f435c77fbb9c9eab1

[176] Expose MessagePort to AudioWorklet · Issue #3081 · whatwg/html () https://github.com/whatwg/html/issues/3081

[177] Fix 3081: Expose MessagePort in AudioWorklet by hoch · Pull Request #3082 · whatwg/html () https://github.com/whatwg/html/pull/3082

[178] Make MessageChannel's close() set [[Detached]] (annevk著, ) https://github.com/whatwg/html/commit/ee5ff06ce0f13ecd73ab4461983f6faec7e88a7a

[180] Make MessagePort's close() set [[Detached]] by annevk · Pull Request #3584 · whatwg/html () https://github.com/whatwg/html/pull/3584

[181] Make MessagePort's close() detach by annevk · Pull Request #10123 · w3c/web-platform-tests () https://github.com/w3c/web-platform-tests/pull/10123

[182] Mobile SafariMessagePort<input type=file>iOS の画像選択に一旦遷移して戻ってくると、 何を送っても相手に届かない状態になる??