* 仕様書

[REFS[
- [31] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2016-12-05 14:51:53 +09:00]]) <https://html.spec.whatwg.org/#channel-messaging>
-- [26] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2016-12-05 14:51:53 +09:00]]) <https://html.spec.whatwg.org/#message-channels>
-- [32] '''[CITE@en-US-x-hixie[HTML Standard]] ([TIME[2016-12-05 14:51:53 +09:00]]) <https://html.spec.whatwg.org/#message-ports>'''
--- [65] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-03-28 21:58:58 +09:00]] 版) <https://www.whatwg.org/specs/web-apps/current-work/#port-message-queue>
--- [66] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2013-02-09 02:07:40 +09:00]] 版) <https://www.whatwg.org/specs/web-apps/current-work/#unshipped-port-message-queue>
--- [92] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2016-12-05 14:51:53 +09:00]]) <https://html.spec.whatwg.org/#dom-messageport-postmessage>
--- [108] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2016-12-05 14:51:53 +09:00]]) <https://html.spec.whatwg.org/#ports-and-garbage-collection>
- [149] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2016-12-06 07:17:59 +09:00]]) <https://html.spec.whatwg.org/#the-worker's-ports>
- [161] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2016-12-13 09:04:33 +09:00]]) <https://html.spec.whatwg.org/#dom-messageevent-ports>
]REFS]

* 作成

[36] [CODE(DOMi)@en[MessagePort]] [[インターフェイス]]は[[コンストラクター]]を持ちません。

[37] 作成するには、 [CODE(DOMi)@en[MessageChannel]] [[オブジェクト]]などを作成する必要があります。

-*-*-

[39] [[環境設定群オブジェクト]][VAR[所有者]]に関する[DFN[[RUBYB[新しい[CODE(DOMi)@en[MessagePort]]オブジェクトの作成]@en[create a new [CODE(DOMi)@en[MessagePort]] object]]]]は、
次のようにしなければ[MUST[なりません]]。

[FIG(steps)[
= [41] [VAR[ポート]]を、新しい [CODE(DOMi)@en[MessagePort]] に設定します [SRC[>>32]]。
[FIG(list members)[ [42] [CODE(DOMi)@en[MessagePort]]
: [F[所有者][MessagePort]] : [VAR[所有者]]
]FIG]
= [128] ([[イベントループ]]の[F[タスクキュー群]]のいずれかの[[タスクキュー]]において、
[VAR[ポート]]の[F[ポートメッセージキュー]]が[[タスクキュー部分リスト]]の1つとなります。)
= [127] [VAR[ポート]]を返します [SRC[>>32]]。
]FIG]

[40] この処理は、次の場面から呼び出されます。
[FIG(list middle)[
- [CODE(DOMi)@en[MessageChannel]] [[コンストラクター]]
- [CODE(DOMi)@en[Worker][new Worker]] [[コンストラクター]]
- [CODE(DOMi)@en[SharedWorker]] [[コンストラクター]]
- [[ワーカーを走らせる]]処理
]FIG]

* 文脈

[33] [CODE(DOMi)@en[MessagePort]] [[インターフェイス]]は、
[[文書環境]]と[[ワーカー環境]]と [CODE[AudioWorklet]] に[[晒され]]ています [SRC[>>32]]。

[96] [CODE(DOMi)@en[MessageChannel]] [[オブジェクト]]を作成すると、
[CODE[port1]] と [CODE[port2]] の2つの [[IDL属性]]から
[CODE(DOMi)@en[MessagePort]] にアクセスできます。

[98] [CODE(DOMm)@en[postMessage]] [[メソッド]]で送信する [CODE(DOMi)@en[MessagePort]]
を指定できます。

[97] [CODE(DOMm)@en[postMessage]] の受信や[[ワーカー]]の作成で
[CODE(DOMi)@en[MessageEvent]] [[イベント]]が[[発火]]された時は、
[CODE(DOMa)@en[ports]] [[IDL属性]]で [CODE(DOMi)@en[MessagePort]]
の[[配列]]にアクセスできます。

[100] [[ワーカー]]は、[F[暗示的ポート]]として [CODE(DOMi)@en[MessagePort]]
を持ちます。

[101] [CODE(DOMi)@en[SharedWorker]] [[オブジェクト]]は、
[CODE(DOMa)@en[port]] [[IDL属性]]で [CODE(DOMi)@en[MessagePort]]
を持ちます。

-*-*-

[99] [CODE(DOMi)@en[WorkerGlobalScope]] は、
[F[[DFN[[RUBYB[[[ワーカーのポート群]]]@en[the worker's ports]]]]]]として 
[CODE(DOMi)@en[MessagePort]] のリストを保持しています [SRC[>>149]]。

@@ ワーカー内で作成されたポートが自動的に追加されます。暗示的なポートも含まれます。

[170] [[protected worker]] かどうかの判定で参照されます。

[171] [[ワーカーを走らせる]]処理の最後の片付けの段階で [[disentangle]] の実行のため参照されます。

[150] 同様に [CODE(DOMi)@en[Window]] も[DFN[[F[ポート群]]]]を持つと考えられます
(>>107)。

* 状態

[38] [CODE(DOMi)@en[EventTarget]] としての状態に加えて、
次の状態を持ちます。
[FIG(list members)[
: [F[[[entangle]] されたポート]] [SRC[>>32]] :
他の [CODE(DOMi)@en[MessagePort]] [[オブジェクト]]。
>>107 も参照。
: [F[ポートメッセージキュー]] :
[[タスク源]]。
[[タスクキュー部分リスト]]と捉えることもできます。 
初期状態は空です。
[[有効]]か[[無効]]かのいずれかの[F[状態]]を持ち、その初期状態は[[無効]]です。
: [F[既に出荷済み]]フラグ :
[[ブール型]]。
初期状態は[[偽]]。
: [DFN[[F[[RUBYB[所有者]@en[owner]]][MessagePort]]]] :
[[環境設定群オブジェクト]]。
[SRC[>>32]]

]FIG]

* メンバー

[34] [CODE(DOMi)@en[EventTarget]] を[[継承]]しています [SRC[>>32]]。

[35] 加えて、次の[[メンバー][インターフェイスメンバー]]があります。
[FIG(short list)[
- [CODE(DOMm)@en[close][MessagePort]]
- [CODE(DOMm)@en[postMessage]]
- [CODE(DOMm)@en[start][MessagePort]]
- [CODE(DOMa)@en[onmessage]]
- [CODE(DOMa)@en[onmessageerror]]
]FIG]

* ポートメッセージキュー

[135] [CODE(DOMi)@en[MessagePort]] [[オブジェクト]]は、
[DFN[[F[[RUBYB[[[ポートメッセージキュー]]]@en[port message queue]]]]]]を持ちます。
初期状態は空です。 [SRC[>>65]]

[136] [CODE(DOMi)@en[MessagePort]] [[オブジェクト]]の[F[ポートメッセージキュー]]は、
[RUBYB[[[無効]]]@en[disabled]]または[RUBYB[[[有効]]]@en[enabled]]のいずれかの[F[状態]]にあります。
初期状態は[[無効]]です。一旦これを[[有効]]にすると、[[無効]]には戻せません。
[SRC[>>65]]

;; [125] [[ポートメッセージキュー]]は、[[タスクキュー部分リスト]]と理解できます。
[[タスクキュー]]を参照。

[137] [CODE(DOMi)@en[MessagePort]] [[オブジェクト]]は、
[DFN[[F[[RUBYB[既に出荷済み][has been shipped]]][has been shipped]]]]フラグを持ちます。
初期状態は[[偽]]です。  
[SRC[>>32]]

@@
[142] 未出荷済み

-*-*-

[64] 2つの状態が、 [CODE(DOMm)@en[postMessage]] の結果生じる
[CODE(DOMe)@en[message][onmessage]] [[イベント]]の実行タイミングに影響します。
[[仕様書]]の規定は複雑でわかりにくいですが:
[FIG(list)[
- [F[既に出荷済み]]フラグが[[偽]]
-- [F[ポートメッセージキュー]]の[F[状態][ポートメッセージキュー]]が[[有効]]
--- [[ポートメッセージキュー]]は実行されない
--- [[未出荷済みポートメッセージキュー]]に'''含まれる'''
-- [F[ポートメッセージキュー]]の[F[状態][ポートメッセージキュー]]が[[無効]]
--- [[ポートメッセージキュー]]は実行されない
--- [[未出荷済みポートメッセージキュー]]に含まれない
- [F[既に出荷済み]]フラグが[[真]]
-- [F[ポートメッセージキュー]]の[F[状態][ポートメッセージキュー]]が[[有効]]
--- [[ポートメッセージキュー]]は'''実行される'''
--- [[未出荷済みポートメッセージキュー]]に含まれない
-- [F[ポートメッセージキュー]]の[F[状態][ポートメッセージキュー]]が[[無効]]
--- [[ポートメッセージキュー]]は実行されない
--- [[未出荷済みポートメッセージキュー]]に含まれない
]FIG]
... 整理してみると単純な話で、キューの状態が有効なら実行され、
出荷済みなら[[ポートメッセージキュー]]扱い、
未出荷なら[[未出荷済みポートメッセージキュー]]扱いになる、ということです。

-*-*-

[143] [[ポートメッセージキュー]]と[[未出荷済みポートメッセージキュー]]は、
[[タスク]]の[[キュー]]であるにも関わらず、[[タスク源]]である [SRC[>>32]]
と規定されています。それでいて、[[イベントループ]]によって
(実行されるべき[[タスク]]のリストとして) 使われる [SRC[>>32]] ともされていて、
[[イベントループ]]の持つ[[タスクキュー]]の一種であるかのようにも捉えられます。

[144] [[仕様書]]の履歴を辿ってみると、元は[[ポートメッセージキュー]]はその名の通り
[CODE(DOMe)@en[message]] ''[[イベント]]''の[[キュー]]でした。
この[[キュー]]に追加された[[イベント]]は、(準備が整い次第)
[[イベント]]を[[発火]]する[[タスク]]が[[イベントループ]]の[[タスクキューに追加][タスクをキューに追加]]され、
[[ポートメッセージキュー]]からは削除されることになっていました。

[145] これがその後の改訂 [SRC[>>133]] で、[[ポートメッセージキュー]]自体が[[タスク]]の[[キュー]]になりました。
[[コミットメッセージ]]で [CODE(DOMi)@en[MessagePort]] 
が他の[[イベントループ]]に渡った時に[[イベント]]が失われないための変更だと説明されており、
[CODE(DOMi)@en[MessagePort]] の [[Transfer]] で[[イベント]]を新[[イベントループ]]下に移動させることが狙いだったようです。

[146] この変更で、[[ポートメッセージキュー]]は[[タスク源]]であるということになりました。
[[仕様書]]は「[[タスク]]は[[タスク源]]から来る」としか言っておらず、
[[タスク源]]とは何なのか (ラベルなのかリストなのか) はよくわかりませんが、
(実装でどう扱うかは別として、[[仕様書]]の裏の考え方としては)
[[タスク源]]とはそれ自体が[[タスク]]の[[リスト]] ([[タスクキュー部分リスト]]) で、
そのような[[リスト]]をいくつか束ねたものが[[タスクキュー]]だ、
といえるのかもしれません。

;; [[タスクキュー]]参照。

-*-*-

[63] [[クライアントメッセージキュー]]と似ています。

* 処理

** entangle

[43] 2つの [CODE(DOMi)@en[MessagePort]] を関連付けた状態とすることを
[DFN[entangle]] といいます。
[VAR[ポート1]]と[VAR[ポート2]]の [[entangle]] は、次のようにしなければ[MUST[なりません]]。

[FIG(steps)[
= [44] [VAR[ポート1]]の [F[[[entangle]] されたポート]]が [CODE[null]] でなければ、
== [45] [VAR[ポート1]]の [[disentangle]] を実行します。 [SRC[>>32]]
= [46] [VAR[ポート2]]の [F[[[entangle]] されたポート]]が [CODE[null]] でなければ、
== [47] [VAR[ポート2]]の [[disentangle]] を実行します。 [SRC[>>32]]
= [48] [VAR[ポート1]]の [F[[[entangle]] されたポート]]を、[VAR[ポート2]]に設定します。 [SRC[>>32]]
= [49] [VAR[ポート2]]の [F[[[entangle]] されたポート]]を、[VAR[ポート1]]に設定します。 [SRC[>>32]]
= [151] [VAR[ポート1]]の[F[所有者][MessagePort]]と[VAR[ポート2]]の[F[所有者][MessagePort]]が異なるなら、
(>>107)
== [152] [VAR[ポート1]]の[F[所有者][MessagePort]]の[F[大域オブジェクト]]の[F[ポート群]]に、
[VAR[ポート1]]を追加します。
== [153] [VAR[ポート2]]の[F[所有者][MessagePort]]の[F[大域オブジェクト]]の[F[ポート群]]に、
[VAR[ポート2]]を追加します。
]FIG]

[51] [[entangle]] は、次の場面で呼び出されます。
[FIG(middle list)[
- [CODE(DOMi)@en[MessagePort]] の [F(ss)[Transfer]]
- [CODE(DOMi)@en[MessageChannel]] [[コンストラクター]]
- [[ワーカーを走らせる]]
- [CODE(DOMi)@en[SharedWorker]] [[コンストラクター]]
]FIG]

[50] この処理が済んだ状態を、[VAR[ポート1]]と[VAR[ポート2]]が 
[DFN[[RUBYB[entangle されている]@en[entangled]]]]といいます [SRC[>>32]]。

[102] [[entangle]] 状態を解除することを、 [DFN[disentangle]] [SRC[>>32]] といいます。
[CODE(DOMi)@en[MessagePort]] [VAR[ポート]]の [[disentangle]] は、
次のようにしなければなりません。

[FIG(steps)[
= [103] [VAR[ポート]]の [F[[[entangle]] されたポート]]の [F[[[entangle]] されたポート]]を、
[CODE[null]] に設定します。
= [155] [VAR[ポート]]の [F[[[entangle]] されたポート]]の[F[所有者][MessagePort]]の[F[大域オブジェクト]]の[F[ポート群]]から、
[VAR[ポート]]の [F[[[entangle]] されたポート]]を (あれば) 削除します (>>107)。
= [104] [VAR[ポート]]の [F[[[entangle]] されたポート]]を、 [CODE[null]] に設定します。
= [154] [VAR[ポート]]の[F[所有者][MessagePort]]の[F[大域オブジェクト]]の[F[ポート群]]から、
[VAR[ポート]]を (あれば) 削除します (>>107)。
]FIG]

[105] [[disentangle]] は、次の場面で呼び出されます。
[FIG(list middle)[
- [[entangle]]
- [CODE(DOMm)@en[close][MessagePort]] [[メソッド]]
- [[ワーカーを走らせる]]処理の最後の破棄の段階
]FIG]

[106] [[entangle]] の中から [[disentangle]] が呼び出される、つまり [[entangle]]
関係が書き換えられて他の [CODE(DOMi)@en[MessagePort]] と関連付けられた状態になるのは、
[F(ss)[Transfer]] からの呼び出しの場合のみです。すなわち [CODE(DOMm)@en[postMessage]]
により [CODE(DOMi)@en[MessagePort]] が送られて、他方の
[CODE(DOMi)@en[MessagePort]] の接続先が新しい方に差し替えられる場合です。
これ以外で [[disentangle]] された [CODE(DOMi)@en[MessagePort]] は、二度と
[CODE(DOMi)@en[entangle]] されることはありません。

** transfer

[52] [CODE(DOMi)@en[MessagePort]] [[オブジェクト]]は、 [[transferable object]]
です。 [SRC[>>32]]

[53] [CODE(DOMi)@en[MessagePort]] [[オブジェクト]]の
[[transfer steps]] は、[VAR[値]]と[VAR[データ保持子]]について、
次のようにしなければ[MUST[なりません]] [SRC[>>32]]。

[FIG(steps)[
= [54] [VAR[値]]を[[出荷]]します。
= [165] [VAR[データ保持子]]の [F(ss)[PortMessageQueue]] を、
[VAR[値]]の[F[ポートメッセージキュー]]に設定します。
= [58] [VAR[遠隔ポート]]を、
[[文脈オブジェクト]]の [F[[[entangle]] されたポート]]に設定します。
= [59] [VAR[遠隔ポート]]が [CODE[null]] 以外なら、
== [60] [VAR[遠隔ポート]]を[[出荷]]します。
== [166] [VAR[データ保持子]]の [F(ss)[RemotePort]] を、[VAR[遠隔ポート]]に設定します。
= [167] それ以外の場合、
== [168] [VAR[データ保持子]]の [F(ss)[RemotePort]] を、 [CODE[null]] に設定します。
]FIG]

[169] [[transfer-receiving steps]] は、[VAR[データ保持子]]と[VAR[値]]について、
次のようにします [SRC[>>32]]。

[FIG(steps)[
= [84] [VAR[値]]を[[出荷]]します。
= [55] [VAR[値]]の[F[所有子][MessagePort]]を、
[VAR[値]]の[F[関連設定群オブジェクト]]に設定します。
= [57] [VAR[データ保持子]]の [F(ss)[PortMessageQueue]] が空でなければ、繰り返し、
== [123] [VAR[タスク]]を、 [VAR[データ保持子]]の [F(ss)[PortMessageQueue]] を
[[dequeue]] した結果に設定します。
== [124] [VAR[タスク]]を[VAR[値]]に transfer (>>126) します。
= [56] [VAR[データ保持子]]の [F(ss)[RemotePort]] が [CODE[null]] 以外なら、
== [61] [VAR[データ保持子]]の [F(ss)[RemotePort]] と[VAR[値]]を [[entangle]] します。
]FIG]

[126] [VAR[旧タスク]]の[VAR[新ポート]]への transfer は、
次のようにしなければ[MUST[なりません]]。
[FIG(steps)[
= [138] [[タスクをキューに追加]]します。
[FIG(list members)[
: [VAR[イベントループ]] : [VAR[新ポート]]の[F[所有者][MessagePort]]の[F[有責イベントループ]]
: [VAR[処理]] : 
[FIG(list members)[ [[引数]]付きの[[アルゴリズム]]
: [F[変数]] : 
[FIG(list members)[
: [VAR[最終対象ポート]] : [VAR[新ポート]] [SRC[>>92]]
]FIG]
: [F[処理]] : [VAR[旧タスク]]の[F[処理]]の[F[処理]]
]FIG]
: [VAR[タスク源]] : [VAR[新ポート]]の[F[ポートメッセージキュー]] [SRC[>>32]]
: [VAR[文脈]] : [VAR[新ポート]]の[F[所有者][MessagePort]] [SRC[>>32]]
]FIG]
]FIG]

;; [140] [[仕様書]]では[[タスクをキューに追加]]する操作を使わずに記述されています。

** ポートの状態の変更

[67] [CODE(DOMi)@en[MessagePort]] [VAR[ポート]]の[DFN[[F[ポートメッセージキュー]]の有効化]]は、
次のようにしなければ[MUST[なりません]] [SRC[>>32]]。
[FIG(steps)[
= [70] [VAR[ポート]]の[F[ポートメッセージキュー]]の[F[状態]]を、[[有効]]に設定します。
]FIG]

[68] これによって、それまで[[イベントループ]]の[[タスクキュー]]の処理で無視されていた本[[ポートメッセージキュー]]の[[タスク]]が、処理対象にと変化します。

;; [[タスクキュー]]参照。

[91] 次の場面で呼び出されます。
[FIG(list middle)[
- [CODE(DOMm)@en[start][MessagePort]]
- [CODE(DOMa)@en[onmessage]]
- [[ワーカーを走らせる]]
]FIG]

;; [130] [[クライアントメッセージキュー]]の
[CODE(DOMm)@en[startMessages]] [[メソッド]]に相当します。

-*-*-

[85] [CODE(DOMi)@en[MessagePort]] [VAR[ポート]]の[DFN[出荷]]は、
次のようにしなければ[MUST[なりません]] [SRC[>>32]]。
[FIG(steps)[
= [86] [VAR[ポート]]の[F[既に出荷済み]]フラグを、[[真]]に設定します。
= [69] [VAR[ポート]]について[[ポート出荷に伴うタスク移動]]を行います。
]FIG]

[87] [CITE[HTML Standard]] では、これは [F(ss)[Transfer]] (>>53) から実行される処理となっています。
意味的には、それ以外に[[ワーカーを走らせる]]処理、 [CODE(JS)@en[new Worker]]、
[CODE(JS)@en[new SharedWorker]] からも実行されるべきではないかとも思われますが、
そうは規定されていません。歴史的経緯による誤りなのか、意図通りなのかははっきりしません。
現実問題どれだけその差が観測できるかは微妙なところかもしれません。

;; それぞれの項も参照。

** ポートメッセージキューの操作

[71] [VAR[処理]]を [CODE(DOMi)@en[MessagePort]] 
[VAR[ポート]]の[DFN[ポートメッセージキューに追加]]するには、
次のようにしなければ[MUST[なりません]]。

[FIG(steps)[
= [138] [[タスクをキューに追加]]します。
[FIG(list members)[
: [VAR[イベントループ]] : [VAR[ポート]]の[F[所有者][MessagePort]]の[F[有責イベントループ]]
: [VAR[処理]] :
[FIG(list members)[ [[引数]]付きの[[アルゴリズム]]
: [F[変数]] : 
[FIG(list members)[
: [VAR[対象Realm]] : [VAR[ポート]]の[F[関連Realm]] [SRC[>>92]]
]FIG]
: [F[処理]] : [VAR[処理]]
]FIG]
: [VAR[タスク源]] :
[VAR[ポート]]の[F[ポートメッセージキュー]] [SRC[>>92]]
: [VAR[文脈]] : [VAR[ポート]]の[F[所有者][MessagePort]] [SRC[>>92]]
]FIG]
]FIG]

;; [147] [[仕様書]]では[[タスクをキューに追加]]する操作を使わずに記述されています。

[129] これは [CODE(DOMm)@en[postMessage]] から呼び出されます。

** ごみ収集

[107] 
[CODE(DOMi)@en[MessagePort]] [VAR[ポート]]が [[entangle]] されているなら、
次の''いずれか''としなければ[MUST[なりません]] [SRC[>>108]]。
[FIG(list)[
- [118] [VAR[ポート]]の[F[[[entangle]] されているポート]]から[VAR[ポート]]へ、
[[強い参照]]が存在する。
- [119] [VAR[ポート]]の[F[所有者][MessagePort]]の[F[大域オブジェクト]]から[VAR[ポート]]へ、
[[強い参照]]が存在する。
]FIG]

[120] 実装上、 [[entangle]] されているポート同士が異なる[[プロセス]]で動作しているなど、
直接[[強い参照]]を保持しているとすると実現困難な場合があるため、
2つの方法が認められているものと思われます。2つの方法は完全に等価なわけではありませんが、
[[著者]]の[[スクリプト]]から直接観測可能な挙動としては同一です。

[139] [[ワーカー]]に関しては、 [CODE(DOMi)@en[WorkerGlobalScope]]
の[F[ワーカーのポート群]]として当該[[ワーカー]]外に [[entangle]] されたすべての
[CODE(DOMi)@en[MessagePort]] のリストを[[大域オブジェクト]]が保持することになっています。
これは事実上 >>119 を求めるものです (他の等価な実装方法も理論上はあり得ますが...)。
[[文書環境]]に関しても、同様に [CODE(DOMi)@en[MessagePort]] のリストを保持するのが現実的でしょう。

[157] 実装上は、 [[disentangle]] されないまま両端とも[[スクリプト]]から参照されなくなった時に、
[F[ポート群]]から除去されてこれらが[[ごみ収集]]されるよう、注意が必要です。

[148] 同じ環境内のポート同士は、 >>118 の方法を採っても、 >>119 の方法に準ずることにしても良さそうです。

[121] [CODE(DOMi)@en[MessagePort]] が[[ごみ収集]]されないということは、
そこに登録された[[イベントリスナー]]が[[ごみ収集]]されないということです。
つまりこの要件は、[[イベントリスナー]]を登録した後に [CODE(DOMi)@en[MessagePort]]
への参照が破棄されたとしても、相手方のポートが生きている限りは[[イベントリスナー]]が呼び出される可能性を維持するためのものです。

;; [122] もちろん、両側の [CODE(DOMi)@en[MessagePort]] が共に参照されない状態になった場合は、
もう[[イベントリスナー]]が呼び出される可能性はありませんから、両方共に破棄できます
[SRC[>>108]]。

[109] 未実行の[[タスク]]と [CODE(DOMi)@en[MessagePort]] の[[ごみ収集]]の関係として、
次のように規定されています。
[FIG(list)[
- [113] 当該[[オブジェクト]]で[[イベント]]を[[ディスパッチ]]する[[タスク]]が[[タスクキュー]]に入っているなら、[[ごみ収集]]しては[MUST[ならない]] [SRC[>>108]]。
- [114] 当該[[オブジェクト]]の[F[[[ポートメッセージキュー]]の状態]]が[[有効]]で、
[F[ポートメッセージキュー]]が空ではないなら、[[ごみ収集]]しては[MUST[ならない]] [SRC[>>108]]。
]FIG]

[115] このうち >>113 は通常の[[タスク]]であれば当然に[[タスク]]から[[イベント対象]]への[[強い参照]]が維持されているはずと考えられるところ、
[CODE(DOMe)@en[message][onmessage]] については実行時点で含まれる[[ポートメッセージキュー]]の
[CODE(DOMi)@en[MessagePort]] を[[イベント対象]]とする (>>71)
との変則的な規定があるための条件なのでしょうか。

[116] >>114 は、逆に言えば[[ポートメッセージキュー]]が無効の場合は実行されずに捨てられる
(かもしれない) し、空になったら捨てられる (かもしれない) ということです。

[117] >>113 は >>114 に含まれるようにも読めますが、[[イベントループ]]が[[タスク]]を実行しようとして[[ポートメッセージキュー]]から取り出した瞬間に空になって
[CODE(DOMi)@en[MessagePort]] が破棄されないために >>113 が必要なのでしょうか。
と思いましたが[[タスク]]は実行が終わるまで[[タスクキュー]]に残ったままですよね...

[131] >>113 は[[タスクキュー]]に[[タスク]]が入っていれば、という規定になっていて、
[[ポートメッセージキュー]]とは言っていません。[[ポートメッセージキュー]]は[[タスク源]]であるとはされていますが、
[[タスクキュー]]とはされていません (いかにも[[タスクキュー]]っぽい名前ですが)。
従って[[ポートメッセージキュー]]が無効なら、 >>113 の条件には合致しないものと思われます。
(無効のまま [CODE(DOMi)@en[MessagePort]] が破棄されたなら、有効化する手段がなくなるので、
捨てても捨てなくても観測できません。)

[156] 現実には [CODE(DOMi)@en[MessagePort]] が無効のまま破棄された時、
[[タスクキュー]]内に[[ポートメッセージキュー]]の[[タスク]]
(が[[イベント対象]]として保持している [CODE(DOMi)@en[MessagePort]] 自身への参照)
も[[ごみ収集]]されるよう、注意する必要があります。

* [CODE(DOMi)@en[MessageChannel]] インターフェイス [CODE(DOMa)@en[port1]] 属性、 [CODE(DOMa)@en[port2]] 属性

[27] [CODE(DOMi)@en[MessageChannel]] [[インターフェイス]]の
[DFN[[CODE(DOMa)@en[port1]]]] [[IDL属性]]と
[DFN[[CODE(DOMa)@en[port2]]]] [[IDL属性]] [SRC[>>26]]
は、それぞれ[[文脈オブジェクト]]の[F[ポート1]]と[F[ポート2]]を返します。

[28] [CODE(DOMi)@en[MessageChannel]] [[オブジェクト]]の[DFN[[F[ポート1]]]]と[DFN[[F[ポート2]]]]は、
[[コンストラクター]]によって新たに作成された [CODE(DOMi)@en[MessagePort]]
[[オブジェクト]]がそれぞれに設定されます。これらの値は変化することはありません。

[29] 2つのポートは、作成された時点では (異なる[[オブジェクト]]であることを除けば)
まったく同じ初期状態です。どちらをどう使うかは、[[著者]]が決めることができます。

[EG[
[30] 例えば [CODE[port1]] の側を [CODE[postMessage]] で通信の相手先に渡したら、
以後のこちら側の送受信には [CODE[port2]] を使うことになります。
逆に [CODE[port2]] を渡したら、 [CODE[port1]] を使うことになります。
]EG]

* [CODE(DOMi)@en[MessagePort]] インターフェイス [CODE(DOMm)@en[start][MessagePort]] メソッド

[88] [CODE(DOMi)@en[MessagePort]] [[インターフェイス]]の
[DFN[[CODE(DOMm)@en[start][MessagePort]]]]
[[メソッド]]は、次のようにしなければ[MUST[なりません]] [SRC[>>32]]。

[FIG(steps)[
= [89] [[文脈オブジェクト]]の[F[[[ポートメッセージキュー]]の状態]]が[[無効]]なら、
== [90] [[文脈オブジェクト]]の[[ポートメッセージキューの有効化]]を実行します。
]FIG]

* [CODE(DOMi)@en[MessagePort]] インターフェイス [CODE(DOMm)@en[close][MessagePort]] メソッド

[93] [CODE(DOMi)@en[MessagePort]] [[インターフェイス]]の
[DFN[[CODE(DOMm)@en[close][MessagePort]]]]
[[メソッド]]は、次のようにしなければ[MUST[なりません]] [SRC[>>32]]。

[FIG(steps)[
= [179] [[文脈オブジェクト]]の [F(ss)[Detached]] を、[[真]]に設定します。
= [94] [[文脈オブジェクト]]の[F[[[entangle]] されたポート]]が [CODE[null]] 以外なら、
== [95] [[文脈オブジェクト]]の [[disentangle]] を実行します。
]FIG]

[112] [CODE(DOMi)@en[[[MessagePort]]]] が不要になったら、明示的に閉じて [[disentangle]]
することが[RUBYB[強く勧められています]@en[strongly encouraged]]。
明示的に閉じずないと必ずしも即座に[[ごみ収集]]されるとは限らないため (>>107)、
[[メモリー]]を無駄にすることとなります。 [SRC[>>108]]

* [CODE(DOMi)@en[MessageEvent]] インターフェイス [CODE(DOMa)@en[ports]] 属性

[162] [CODE(DOMi)@en[MessageEvent]] [[インターフェイス]]と
[CODE(DOMi)@en[MessageEventInit]] [[辞書]]の
[DFN[[CODE(DOMa)@en[ports]]]]
[[IDL属性]]/[[辞書メンバー]] [SRC[>>161]] は、
受信した [CODE(DOMi)@en[MessagePort]] の[[配列]]を表します。

[163] 値は [CODE(DOMi)@en[MessagePort]] の [CODE[sequence][sequence<>]] です
[SRC[>>12]]。[[辞書]]での既定値は[[空]]の[[配列]]です [SRC[>>12]]。

* 歴史

[REFS[
- [72] [CITE@en['''['''''']''' (0) Simplify message ports: use queueing instead of transient 'act…]] ([[Hixie]]著, [TIME[2008-08-06 16:24:38 +09:00]]) <https://github.com/whatwg/html/commit/ebefa1c712950ea904e2e4877caa13db8b1d9104>
]REFS]

[73] [[ポートメッセージキュー]]はここで導入されました。
open と closed の2つの状態を持っていました。
この時同時に追加された [CODE[start]] [[メソッド]]を呼び出すか、
[CODE[onmessage]] [[IDL属性]]に値を設定するかのいずれかにより、
closed から open へと遷移することとされていました。

[REFS[
- [110] [CITE@en[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.]] ([TIME[2008-08-06 16:57:00 +09:00]] 版) <http://html5.org/tools/web-apps-tracker?from=2023&to=2024>
- [132] r2043 [CITE@en['''['''''']''' (0) Add a startConversation() method that wraps new MessageChannel…]] ([[Hixie]]著, [TIME[2008-08-11 16:34:01 +09:00]]) <https://github.com/whatwg/html/commit/8f86a0c7e1ce7d2f99102378720a47dd3766083d>
- [74] [CITE@en[Web Applications 1.0 r2085 Further work on the event loop front. (WebSockets, postMessage, MessagePorts, setTimeout)]]
([TIME[2008-08-19 18:30:00 +09:00]] 版)
<https://html5.org/r/2085>
- [111] [CITE@en[Web Applications 1.0 r2357    Define MessagePort such that they won't be garbage collected while a message is outstanding. (credit: ap)]] ([TIME[2008-10-21 04:18:00 +09:00]] 版) <http://html5.org/tools/web-apps-tracker?from=2356&to=2357>
- [75] [CITE@en['''['''gwr''']''' (2) MessagePorts shouldn't be GCed even when their queue is clo…]] ([[Hixie]]著, [TIME[2008-10-21 19:24:55 +09:00]]) <https://github.com/whatwg/html/commit/7c0d06509cbfc808e06aac3b4ae8edafbf0a771c>
- [76] [CITE@en[Web Applications 1.0 r2531    Simplify the way messages in ports are handled when the destination's document is not available.]]
([TIME[2008-12-16 10:01:00 +09:00]] 版)
<https://html5.org/r/2531>
- [133] r2532 [CITE@en['''['''gw''']''' (2) Drop MessagePort.onclose. Make MessagePort's message queue a…]] ([[Hixie]]著, [TIME[2008-12-16 10:33:52 +09:00]]) <https://github.com/whatwg/html/commit/7ec8efc310084ea89b71358dd070f535a1e43904>
]REFS]

[134] これまで[[投稿済みメッセージタスク源]]が使われていましたが、
>>133 により、使われなくなりました。

[REFS[
- [77] [CITE@en[Web Applications 1.0 r2912 Implicitly open the port message queue of dedicated workers. (Before, they would never actually receive messages, oops...)]]
([TIME[2009-03-26 08:08:00 +09:00]] 版)
<https://html5.org/r/2912>
- [78] [CITE@en[Web Applications 1.0 r6384 Give more explanation about how workers work.]]
([TIME[2011-08-09 05:10:00 +09:00]] 版)
<https://html5.org/r/6384>
- [79] [CITE@en[Web Applications 1.0 r7669     Make MessagePort objects synchronised until they are posted through another port.]] ([TIME[2013-01-30 05:59:00 +09:00]] 版) <http://html5.org/tools/web-apps-tracker?from=7668&to=7669>
- [80] [CITE@en[Web Applications 1.0 r8153  Disabled port message queues shouldn't have their messages dispatched when they're still unshipped, nor should they stall the entire message queueing mechanism.]]
([TIME[2013-08-27 02:59:00 +09:00]] 版)
<https://html5.org/r/8153>
- [81] [CITE@en[Web Applications 1.0 r8154 Reorganise the stuff about port message queues to be clearer.]]
([TIME[2013-08-27 03:02:00 +09:00]] 版)
<https://html5.org/r/8154>
- [82] [CITE@en['''['''giow''']''' (0) Make sure subsequent owners of an ill-fated port's friend …]] ([[Hixie]]著, [TIME[2013-12-12 04:51:50 +09:00]]) <https://github.com/whatwg/html/commit/3d29c3388dd70a93f4d1704f6f3ba5a32a7dd20e>
- [83] [CITE@en[Web Applications 1.0 r8864 Fix the mess I made of port message queues. I'm pretty sure originally they weren't task sources and I corrupted them at some point to be that without changing what I was putting in them. Anyway at this point it's easier just to say that they're real task sources and thus have tasks, even if those tasks have to now be a little more complicated than ideal.]]
([TIME[2014-11-27 09:29:00 +09:00]] 版)
<https://html5.org/r/8864>
]REFS]

[1] [CITE[IRC logs: freenode / #whatwg / 20130604]]
( ([TIME[2013-06-06 22:25:38 +09:00]] 版))
<http://krijnhoetmer.nl/irc-logs/whatwg/20130604>

[2] [CITE[''''''[''''''whatwg'''''']'''''' onclose events for MessagePort]]
( ([TIME[2013-10-29 23:45:30 +09:00]] 版))
<http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2013-October/041298.html>

[3] [CITE@en[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.)]]
( ([TIME[2013-11-22 08:48:00 +09:00]] 版))
<http://html5.org/tools/web-apps-tracker?from=8305&to=8306>

[4] [CITE[''''''[''''''whatwg'''''']'''''' onclose events for MessagePort]]
( ([TIME[2013-12-07 10:22:36 +09:00]] 版))
<http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2013-December/041739.html>

[5] [CITE@en[Web Applications 1.0 r8336     Add a way to catch the other side of a port having a catastrophic death.]]
( ([TIME[2013-12-07 10:22:00 +09:00]] 版))
<http://html5.org/tools/web-apps-tracker?from=8335&to=8336>

[6] [CITE@en[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...).]]
( ([TIME[2013-12-12 02:41:00 +09:00]] 版))
<http://html5.org/tools/web-apps-tracker?from=8340&to=8341>

[7] [CITE[IRC logs: freenode / #whatwg / 20131218]]
( ([TIME[2013-12-20 09:03:33 +09:00]] 版))
<http://krijnhoetmer.nl/irc-logs/whatwg/20131218>

[8] [CITE@en[Web Applications 1.0 r8342     Make sure subsequent owners of an ill-fated port's friend can know about that fate]]
( ([TIME[2013-12-12 04:51:00 +09:00]] 版))
<http://html5.org/tools/web-apps-tracker?from=8341&to=8342>

[9] [CITE[''''''[''''''whatwg'''''']'''''' onclose events for MessagePort]]
( ([TIME[2014-01-31 18:43:03 +09:00]] 版))
<http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2014-January/041953.html>

[10] [CITE@en[Web Applications 1.0 r2020 Make MessagePort objects not be owned by Windows necessarily, and remove ownerWindow.]]
( ([TIME[2008-08-06 09:25:00 +09:00]] 版))
<https://html5.org/r/2020>

[11] [CITE@en[Web Applications 1.0 r2116 Change 'unload' to 'close' for MessagePorts.]]
( ([TIME[2008-08-26 19:36:00 +09:00]] 版))
<https://html5.org/r/2116>

[12] [CITE@en[Web Applications 1.0 r2531    Simplify the way messages in ports are handled when the destination's document is not available.]]
( ([TIME[2008-12-16 10:01:00 +09:00]] 版))
<https://html5.org/r/2531>

[13] [CITE@en[Web Applications 1.0 r2032 Remove redundant event listeners on MessagePort.]]
( ([TIME[2008-08-08 13:14:00 +09:00]] 版))
<https://html5.org/r/2032>

[14] [CITE@en[Web Applications 1.0 r2031 MessagePort should implement EventTarget.]]
( ([TIME[2008-08-07 07:56:00 +09:00]] 版))
<https://html5.org/r/2031>

[15] [CITE@en[Web Applications 1.0 r3346   Allow cloning and posting of closed ports. (credit: dw)]]
( ([TIME[2009-07-01 12:55:00 +09:00]] 版))
<https://html5.org/r/3346>

[16] [CITE@en[Web Applications 1.0 r2885 postMessage() methods that take MessagePort objects now take MessagePortArray objects.]]
( ([TIME[2009-03-21 06:09:00 +09:00]] 版))
<https://html5.org/r/2885>

[17] [CITE@en[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.]]
( ([TIME[2008-08-06 16:57:00 +09:00]] 版))
<https://html5.org/r/2024>

[18] [CITE@en[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.]]
( ([TIME[2009-06-12 12:22:00 +09:00]] 版))
<https://html5.org/r/3227>

[19] [CITE@en[Web Applications 1.0 r3147 Clarify MessagePort GC rules.]]
( ([TIME[2009-05-29 09:38:00 +09:00]] 版))
<https://html5.org/r/3147>

[20] [CITE@en[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)]]
( ([TIME[2008-10-21 19:24:00 +09:00]] 版))
<https://html5.org/r/2358>

[21] [CITE@en[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().]]
( ([TIME[2008-08-06 16:24:00 +09:00]] 版))
<https://html5.org/r/2023>

[22] [CITE@en[Web Applications 1.0 r2357    Define MessagePort such that they won't be garbage collected while a message is outstanding. (credit: ap)]]
( ([TIME[2008-10-21 04:18:00 +09:00]] 版))
<https://html5.org/r/2357>

[23] [CITE@en[Add <script type="module"> and module resolution/fetching/evaluation · whatwg/html@cd1a9fb]]
([TIME[2016-01-29 22:56:17 +09:00]] 版)
<https://github.com/whatwg/html/commit/cd1a9fb1e83f7d0bc30be8b34ecdaf444a0b19a4>

[24] [CITE@en[Write structured clone algorithm in terms of ECMAScript · whatwg/html@bfb960c]]
([TIME[2016-03-02 16:39:51 +09:00]] 版)
<https://github.com/whatwg/html/commit/bfb960c938580c95e77365e614218b952f96375b>

[25] [CITE@en[Use FrozenArray for Navigator#languages and MessageEvent#ports · whatwg/html@e4df68a]]
([TIME[2016-03-25 13:56:53 +09:00]] 版)
<https://github.com/whatwg/html/commit/e4df68a41b86753c7fcdd0d8ea4615f63ffc87e9>

[158] [CITE@en[28813 – There's no way to tell when a MessagePort is closed.]]
([TIME[2016-12-14 13:18:03 +09:00]])
<https://www.w3.org/Bugs/Public/show_bug.cgi?id=28813>

[159] [CITE@en[Use FrozenArray for Navigator#languages and MessageEvent#ports · whatwg/html@e4df68a]]
([TIME[2016-03-25 13:51:40 +09:00]] 版)
<https://github.com/whatwg/html/commit/e4df68a41b86753c7fcdd0d8ea4615f63ffc87e9>

[160] [CITE@en[Make MessageEvent's ports attribute non-nullable]]
([[cdumez]]著, [TIME[2016-10-11 07:09:55 +09:00]])
<https://github.com/whatwg/html/commit/df2c0c448612d5b8ab85ad3c6ce0255ee11c0b01>

[164] [CITE@en[Breaking: refactor structured clone into serialize/deserialize]]
([[domenic]]著, [TIME[2017-03-21 06:09:33 +09:00]])
<https://github.com/whatwg/html/commit/97d644c97335956610a31e8ad98d1a388c063e84>

[62] [CITE@en[Breaking: refactor structured clone into serialize/deserialize]]
([[domenic]]著, [TIME[2017-03-21 06:09:33 +09:00]])
<https://github.com/whatwg/html/commit/97d644c97335956610a31e8ad98d1a388c063e84>

[141] [CITE@en[Editorial: restructure ownership of workers to parent-owners]]
([[annevk]]著, [TIME[2017-04-14 14:47:44 +09:00]])
<https://github.com/whatwg/html/commit/59a4750f475acd789ee436b4906972ba2081d8b3>

[172] [CITE@en[Editorial: restructure ownership of workers to parent-owners]]
([[annevk]]著, [TIME[2017-04-14 14:47:44 +09:00]])
<https://github.com/whatwg/html/commit/59a4750f475acd789ee436b4906972ba2081d8b3>

[173] [CITE@en[Meta: remove "ILLFATED" MessagePort design]]
([[annevk]]著, [TIME[2017-04-25 22:41:34 +09:00]])
<https://github.com/whatwg/html/commit/1208d255eddebe7efc3bba59bc297709e3b30660>

[174] [CITE@en[Introduce MessagePort on AudioWorkletNode/Processor by hoch · Pull Request #1233 · WebAudio/web-audio-api]]
([TIME[2017-10-01 16:25:43 +09:00]])
<https://github.com/WebAudio/web-audio-api/pull/1233>

[175] [CITE@en[Expose MessagePort to AudioWorklet]]
([[hoch]]著, [TIME[2017-10-03 17:07:58 +09:00]])
<https://github.com/whatwg/html/commit/458347c0d677dbd6e2414d6f435c77fbb9c9eab1>

[176] [CITE@en[Expose MessagePort to AudioWorklet · Issue #3081 · whatwg/html]]
([TIME[2017-10-04 17:06:07 +09:00]])
<https://github.com/whatwg/html/issues/3081>

[177] [CITE@en[Fix 3081: Expose MessagePort in AudioWorklet by hoch · Pull Request #3082 · whatwg/html]]
([TIME[2017-10-04 17:06:39 +09:00]])
<https://github.com/whatwg/html/pull/3082>

[178] [CITE@en[Make MessageChannel's close() set '''[''''''['''Detached''']'''''']''']]
([[annevk]]著, [TIME[2018-04-28 01:57:39 +09:00]])
<https://github.com/whatwg/html/commit/ee5ff06ce0f13ecd73ab4461983f6faec7e88a7a>

[180] [CITE@en[Make MessagePort's close() set '''[''''''['''Detached''']'''''']''' by annevk · Pull Request #3584 · whatwg/html]]
([TIME[2018-05-02 13:31:18 +09:00]])
<https://github.com/whatwg/html/pull/3584>

[181] [CITE@en[Make MessagePort's close() detach by annevk · Pull Request #10123 · w3c/web-platform-tests]]
([TIME[2018-05-02 13:31:35 +09:00]])
<https://github.com/w3c/web-platform-tests/pull/10123>

[182] 
[[Mobile Safari]] の
[CODE[MessagePort]]、
[CODE[<input type=file>]]
で [[iOS]] の画像選択に一旦遷移して戻ってくると、
何を送っても相手に届かない状態になる??
[TIME[2018-09-20T08:51:01.200Z]]