HTML — 通信

9. 通信

注記: この節に定義されていた `WebSocket$I ~interfaceは、 今や, `WebSockets^cite `WEBSOCKETS$r にて定義される。 ◎ The WebSocket interface used to be defined here. It is now defined in WebSockets. [WEBSOCKETS]

【この訳に特有な表記規約】

◎表記記号

9.1. `MessageEvent^I ~interface

次に挙げるものにおいては、 各 `message$et ~eventは, `MessageEvent$I ~interfaceを利用する ⇒# `~server-sent~event$における~message/ `文書間~message法$/ `~channel~message法$/ `~broadcast~channel$/ `WebSockets^cite `WEBSOCKETS$r ◎ Messages in server-sent events, cross-document messaging, channel messaging, broadcast channels, and WebSockets use the MessageEvent interface for their message events: [WEBSOCKETS]

[Exposed=(Window,Worker,AudioWorklet)]
interface `MessageEvent@I : `Event$I {
  `constructor$(DOMString %type, optional `MessageEventInit$I %eventInitDict = {});

  readonly attribute any `data$m;
  readonly attribute USVString `origin$m;
  readonly attribute DOMString `lastEventId$m;
  readonly attribute `MessageEventSource$I? `source$m;
  readonly attribute FrozenArray<`MessagePort$I> `ports$m;

  undefined `initMessageEvent$m(DOMString %type, optional boolean %bubbles = false, optional boolean %cancelable = false, optional any %data = null, optional USVString %origin = "", optional DOMString %lastEventId = "", optional `MessageEventSource$I? %source = null, optional sequence<`MessagePort$I> %ports = []);
};

dictionary `MessageEventInit@I : `EventInit$I {`MessageEventInit^CTX
  any ``data@m = null;
  USVString ``origin@m = "";
  DOMString ``lastEventId@m = "";
  `MessageEventSource$I? ``source@m = null;
  sequence<`MessagePort$I> ``ports@m = [];
};

typedef (`WindowProxy$I or `MessagePort$I or `ServiceWorker$I) `MessageEventSource@I;
%event.`data$m
~messageの~dataを返す。 ◎ Returns the data of the message.
%event.`origin$m
[ `~server-sent~event$/`文書間~message法$ ]の下では、 ~messageの生成元を返す。 ◎ Returns the origin of the message, for server-sent events and cross-document messaging.
%event.`lastEventId$m
`~server-sent~event$の下では、 `最後の~event~ID文字列$eSを返す。 ◎ Returns the last event ID string, for server-sent events.
%event.`source$m
`文書間~message法$の下では、 ~source~window 【送信-元~window】 の `WindowProxy$I を返す。 `SharedWorkerGlobalScope$I ~objに向けて発火された `connect$et ~eventにおいては、 添付されている `MessagePort$Iを返す。 ◎ Returns the WindowProxy of the source window, for cross-document messaging, and the MessagePort being attached, in the connect event fired at SharedWorkerGlobalScope objects.
%event.`ports$m
[ `文書間~message法$/`~channel~message法$ ]の下では、 ~messageに伴われて送信された `MessagePort$I 配列を返す。 ◎ Returns the MessagePort array sent with the message, for cross-document messaging and channel messaging.

`data@m 取得子~手続きは、 初期化-時の値を返す。 ◎ The data attribute must return the value it was initialized to.\

結果は、 送信されてきた~messageを表現する。 ◎ It represents the message being sent.

`origin@m 取得子~手続きは、 初期化-時の値を返す。 ◎ The origin attribute must return the value it was initialized to.\

これは,[ `~server-sent~event$/`文書間~message法$ ]の下では、[ ~messageを送信した文書の`生成元$doc ]を表現する (概して,当の文書の[ ~scheme, ~hostname, ~port ]からなるが、 その[ ~pathや`素片$url ]は含まない)。 ◎ It represents, in server-sent events and cross-document messaging, the origin of the document that sent the message (typically the scheme, hostname, and port of the document, but not its path or fragment).

`lastEventId@m 取得子~手続きは、 初期化-時の値を返す。 ◎ The lastEventId attribute must return the value it was initialized to.\

これは,`~server-sent~event$の下では、[ `EventSource$I ~objの`最後の~event~ID文字列$eS ]を表現する。 ◎ It represents, in server-sent events, the last event ID string of the event source.

`source@m 取得子~手続きは、 初期化-時の値を返す。 ◎ The source attribute must return the value it was initialized to.\

これは, `文書間~message法$の下では、[ ~messageを送ってきた`~window$に`対応する閲覧~文脈$の `WindowProxy$I ]を表現する。 `共用~worker内$で利用される `connect$et ~eventにおいては、 新たに接続している `MessagePort$I になる。 ◎ It represents, in cross-document messaging, the WindowProxy of the browsing context of the Window object from which the message came; and in the connect events used by shared workers, the newly connecting MessagePort.

`ports@m 取得子~手続きは、 初期化-時の値を返す。 ◎ The ports attribute must return the value it was initialized to.\

これは,[ `文書間~message法$/`~channel~message法$ ]の下では、[ ~messageに伴って送信される `MessagePort$I 配列 ]を表現する。 ◎ It represents, in cross-document messaging and channel messaging, the MessagePort array being sent.

`initMessageEvent(type, bubbles, cancelable, data, origin, lastEventId, source, ports)@m ~method~手続きは、[ 似た命名の `initEvent()$m ~methodに相似的な方式 ]で~eventを初期化する。 `DOM$r 【構築子と機能が重複する旧来の~method】 ◎ The initMessageEvent(type, bubbles, cancelable, data, origin, lastEventId, source, ports) method must initialize the event in a manner analogous to the similarly-named initEvent() method. [DOM]

注記: 様々な~API(例: `WebSocket$I や `EventSource$I )が、 `MessagePort$I ~APIを利用せずに, `MessageEvent$I ~interfaceを `message$et ~eventに利用する。 ◎ Various APIs (e.g., WebSocket, EventSource) use the MessageEvent interface for their message event without using the MessagePort API.

9.2. ~server-sent~event

【 この節の内容の和訳は、 `別~page@~HTMLsse$にて。 】

9.3. 文書間~message法

~securityや~privacyの理由から、 ~web~browserは[ 異なる~domainに属する文書どうしが互いに影響しあう ]のを防止する — すなわち、 ~XSSは許容されないようにする。 ◎ Web browsers, for security and privacy reasons, prevent documents in different domains from affecting each other; that is, cross-site scripting is disallowed.

これは重要な~security用の特能であるが、 異なる~domainに属する~pageとの通信は, その~pageが敵対的でなくとも防止される。 この節では、[ ~source~domainに関わらず, 文書どうしが互いに~messageを通信しあえる ]ようにする~systemを[ ~XSS攻撃を可能化しないように設計される仕方 ]で導入する。 ◎ While this is an important security feature, it prevents pages from different domains from communicating even when those pages are not hostile. This section introduces a messaging system that allows documents to communicate with each other regardless of their source domain, in a way designed to not enable cross-site scripting attacks.

注記: `postMessage()$m ~APIは、 `追跡~行路$として利用され得る。 ◎ The postMessage() API can be used as a tracking vector.

9.3.1. 序論

◎非規範的

例えば,ある文書 %A が `iframe$e 要素を包含していて, その要素は 別の文書 %B を包含している下で, %A 内の~scriptが %B の`~window$の `window.postMessage()$m を~callした場合、 ~message~eventは,その~objに向けて発火される — %A の`~window$を出自にしているよう~markされた上で。 %A 内の~scriptは、 次の様になろう: ◎ For example, if document A contains an iframe element that contains document B, and script in document A calls postMessage() on the Window object of document B, then a message event will be fired on that object, marked as originating from the Window of document A. The script in document A might look like:

var %o = document.getElementsByTagName('iframe')[0];
%o.contentWindow.postMessage('Hello world', 'https://b.example.org/');

%B 内の~scriptは、 入って来る~eventに対する~event~handlerを登録するため, `addEventListener()^m (または類似な仕組み)を利用することになる。 例えば、 次の様になろう: ◎ To register an event handler for incoming events, the script would use addEventListener() (or similar mechanisms). For example, the script in document B might look like:

window.addEventListener('message', receiver, false);
function receiver(%e) {
  if (%e.origin == 'https://example.com') {
    if (%e.data == 'Hello world') {
      %e.source.postMessage('Hello', %e.origin);
    } else {
      alert(%e.data);
    }
  }
}

この~scriptは、 まず,~domainが期待されるものかどうか検査する。 次に,~messageの中身に応じて、 利用者に表示するか, ~message送信してきた文書に~messageを返信して応答する。 ◎ This script first checks the domain is the expected domain, and then looks at the message, which it either displays to the user, or responds to by sending a message back to the document which sent the message in the first place.

9.3.2. ~security

9.3.2.1. 作者

[ ~~利己~目的で~siteを濫用する敵対的な実体 ]から利用者を保護するため、 この~APIの利用にあたっては,格別に注意することが要求される。 ◎ Use of this API requires extra care to protect users from hostile entities abusing a site for their own purposes.

作者は、 `origin$m 属性を検査して, 受容する~messageを[ 自身が期待する~domainから受信されるもの ]に限ることを確保するべきである。 作者の~message取扱い~code内に~bugがある場合、 敵対的~siteにより悪用され得ることになる。 ◎ Authors should check the origin attribute to ensure that messages are only accepted from domains that they expect to receive messages from. Otherwise, bugs in the author's message handling code could be exploited by hostile sites.

加えて, `origin$m 属性を検査した後でも、 作者は,[ 当の~dataは、 期待される形式であるかどうか ]を検査するべきである。 さもなければ、[ ~eventの~sourceが~XSSに対する欠陥を突いて攻撃されていた場合 ]に,[ `window.postMessage()$m ~methodで送信された情報 ]は[ 攻撃により受信器にまで伝播する ]ことになる。 ◎ Furthermore, even after checking the origin attribute, authors should also check that the data in question is of the expected format. Otherwise, if the source of the event has been attacked using a cross-site scripting flaw, further unchecked processing of information sent using the postMessage() method could result in the attack being propagated into the receiver.

作者は、[ ~messageのうち,機密的な情報を包含するもの ]においては, 生成元~引数( %targetOrigin )に~wildcard~keyword( `*^l )を渡すべきでない。 そうしない以外に、[ ~messageの送達-先を意図された受信者のみに限る ]よう保証する仕方はない。 ◎ Authors should not use the wildcard keyword (*) in the targetOrigin argument in messages that contain any confidential information, as otherwise there is no way to guarantee that the message is only delivered to the recipient to which it was intended.


どの生成元からの~messageも受容する作者には、 ~DoS攻撃の~riskを考慮することが奨励される — 攻撃者は、 ~~大容量な~messageも送信できるので。 受信している~pageが高価な計算を遂行したり,そのような各~messageの送信ごとに~network流通が生じる場合、 攻撃者の~messageは,~DoS攻撃~用に増殖される。 作者には、[ そのような攻撃が実用的でなくなるよう,~rate制限-法を使役する ]ことが奨励される (毎分あたりの~message数を一定に抑えるなど)。 ◎ Authors who accept messages from any origin are encouraged to consider the risks of a denial-of-service attack. An attacker could send a high volume of messages; if the receiving page performs expensive computation or causes network traffic to be sent for each such message, the attacker's message could be multiplied into a denial-of-service attack. Authors are encouraged to employ rate limiting (only accepting a certain number of messages per minute) to make such attacks impractical.

9.3.2.2. ~UA

この~API 【による~message】 の完全性は、 ある`生成元$の~scriptが[ 任意な~eventを(`同一-生成元$でない)他の生成元に属する~objへ( `dispatchEvent()^m などを利用して)投函できない ]ことに基づいている。 ◎ The integrity of this API is based on the inability for scripts of one origin to post arbitrary events (using dispatchEvent() or otherwise) to objects in other origins (those that are not the same).

注記: 実装者には、 この特能を実装するにあたり, 格別に注意することが督促される。 この特能は、 作者がある~domainから別の~domainへ情報を伝送できるようにする — 通常は,~securityの理由から許容されないような。 また,~UAには、 ある種の~propertyへの~accessを[ 一方には許容しつつ,他方には許容しない ]よう気を付けることが要求される。 ◎ Implementers are urged to take extra care in the implementation of this feature. It allows authors to transmit information from one domain to another domain, which is normally disallowed for security reasons. It also requires that UAs be careful to allow access to certain properties but not others.


簡易的な~siteを~DoS攻撃から保護するため、 ~UAには,[ 異なる`生成元$の間での~message流通~rate ]の制限-法を考慮することが奨励される。 ◎ User agents are also encouraged to consider rate-limiting message traffic between different origins, to protect naïve sites from denial-of-service attacks.

9.3.3. ~messageの投函-法

%window.`~postMessageO(message [, options ])$m
%message を %window へ投函する。 %message は有構造~objにもなり得る。 例えば、 次に挙げるものを包含できる ⇒# 入子な~objや配列/ ~JS値( `string^jT, `number^jT, `Date$jT ~obj, 等々)/ ある種の~data~obj( `File$I, `Blob$I, `FileList$I, `ArrayBuffer$I など) ◎ Posts a message to the given window. Messages can be structured objects, e.g. nested objects and arrays, can contain JavaScript values (strings, numbers, Date objects, etc.), and can contain certain data objects such as File Blob, FileList, and ArrayBuffer objects.
%options の `transfer$m ~member内に~listされた~objは、 ~cloneされるのみならず,転送される — すなわち、 それ以降,それらは 送信-側からは利用-不能になる。 ◎ Objects listed in the transfer member of options are transferred, not just cloned, meaning that they are no longer usable on the sending side.
%options の `targetOrigin$m ~memberを利用して,宛先~生成元を指定できる。 供されない場合の既定は `/^l になる — この既定は、 %message の宛先を同一-生成元のみに制約する。 ◎ A target origin can be specified using the targetOrigin member of options. If not provided, it defaults to "/". This default restricts the message to same-origin targets only.
宛先 %window の生成元が宛先~生成元に合致しない場合、 情報~漏洩eを避けるため, %message は破棄される。 生成元に関わらず %message を宛先へ送信するためには、 宛先~生成元を `*^l に設定する。 ◎ If the origin of the target window doesn't match the given target origin, the message is discarded, to avoid information leakage. To send the message to the target regardless of origin, set the target origin to "*".
次のいずれかに該当する場合、 `DataCloneError$E が投出される ⇒# %transfer 配列が同じ~objを重複して包含している/ %message を~cloneできなかった ◎ Throws a "DataCloneError" DOMException if transfer array contains duplicate objects or if message could not be cloned.
%window.`postMessage(message, targetOrigin [, transfer ])$m
これは、 `postMessage()^m の別~versionであり, 宛先~生成元を~parameterとして指定する。 次の 2 つの~callは等価になる ⇒# window.postMessage(%message, %target, %transfer), window.postMessage(%message, {targetOrigin: %target, transfer: %transfer}) ◎ This is an alternate version of postMessage() where the target origin is specified as a parameter. Calling window.postMessage(message, target, transfer) is equivalent to window.postMessage(message, {targetOrigin, transfer}).

注記: 新たな`文書$へ~navigateされたばかりの`閲覧~文脈$に対応する`~window$に向けて,~messageを投函した場合、 その~messageは,意図した受信者に受信されない見込みが高い — 宛先 `閲覧~文脈$内の~scriptは、 ~message用の~listenerを設定しておく時間を要するので。 したがって、 一例として[ ~messageが 新たに作成された子 `iframe$e の`~window$に送信される状況 ]においては, 作者には次を行うこと勧める ⇒ 子である方の`文書$から先に,受信する用意が整った旨を親~宛に公告する~messageを投函させ、 親は,この~messageを待機してから~messageを投函し始める ◎ When posting a message to a Window of a browsing context that has just been navigated to a new Document is likely to result in the message not receiving its intended recipient: the scripts in the target browsing context have to have had time to set up listeners for the messages. Thus, for instance, in situations where a message is to be sent to the Window of newly created child iframe, authors are advised to have the child Document post a message to their parent announcing their readiness to receive messages, and for the parent to wait for this message before beginning posting messages.

`~windowに~messageを投函する手続き@ は、所与の ( %宛先~window, %~message, %~option群 ) に対し,次に従う: ◎ The window post message steps, given a targetWindow, message, and options, are as follows:

  1. %宛先~realm ~LET %宛先~window の`~realm$gL ◎ Let targetRealm be targetWindow's realm.
  2. %現任な設定群 ~LET `現任な設定群~obj$ ◎ Let incumbentSettings be the incumbent settings object.
  3. %宛先~生成元 ~LET %~option群[ "`targetOrigin$m" ] ◎ Let targetOrigin be options["targetOrigin"].
  4. ~IF[ %宛先~生成元 ~EQ `002F^U ( `/^l ) ] ⇒ %宛先~生成元 ~SET %現任な設定群 の`生成元$enV ◎ If targetOrigin is a single U+002F SOLIDUS character (/), then set targetOrigin to incumbentSettings's origin.
  5. ~ELIF[ %宛先~生成元 ~NEQ `002A^U ( `*^l ) ]: ◎ Otherwise, if targetOrigin is not a single U+002A ASTERISK character (*), then:

    1. %構文解析した~URL ~LET `~URL構文解析する$( %宛先~生成元 ) ◎ Let parsedURL be the result of running the URL parser on targetOrigin.
    2. ~IF[ %構文解析した~URL ~EQ `失敗^i ] ⇒ ~THROW `SyntaxError$E ◎ If parsedURL is failure, then throw a "SyntaxError" DOMException.
    3. %宛先~生成元 ~SET %構文解析した~URL の`生成元$url ◎ Set targetOrigin to parsedURL's origin.
  6. %transfer ~LET %~option群[ "`transfer$m" ] ◎ Let transfer be options["transfer"].
  7. %転送-を伴う直列化-結果 ~LET `StructuredSerializeWithTransfer$jA( %message, %transfer ) (例外投出あり) ◎ Let serializeWithTransferResult be StructuredSerializeWithTransfer(message, transfer). Rethrow any exceptions.
  8. `大域~taskを~queueする$( `投函-済み~message~task~source@†, %宛先~window, 次の手続き ) ◎ Queue a global task on the posted message task source given targetWindow to run the following steps:

    【† この`~task~source$は、 ここでしか利用されない — すなわち、 `~task~queue$を他と共有しない目的で定義されている。 】

    手続きは: ◎ ↑

    1. ~IF[ %宛先~生成元 ~NEQ `002A^U ( `*^l ) ]~AND[ %宛先~window に`結付けられた文書$の`生成元$doc ~NEQ`生成元$sub %宛先~生成元 ] ⇒ ~RET ◎ If the targetOrigin argument is not a single literal U+002A ASTERISK character (*) and targetWindow's associated Document's origin is not same origin with targetOrigin, then return.
    2. %生成元 ~LET `生成元を直列化する$( %現任な設定群 の`生成元$enV ) ◎ Let origin be the serialization of incumbentSettings's origin.
    3. %~source ~LET %現任な設定群 の`大域~obj$enV(`~window$)に対応している `WindowProxy$I ~obj ◎ Let source be the WindowProxy object corresponding to incumbentSettings's global object (a Window object).
    4. %逆直列化-~record ~LET `StructuredDeserializeWithTransfer$jA( %転送-を伴う直列化-結果, %宛先~realm ) ◎ Let deserializeRecord be StructuredDeserializeWithTransfer(serializeWithTransferResult, targetRealm).

      ここで例外が投出されたときは、 ~catchして: ◎ If this throws an exception, catch it,\

      1. `~eventを発火する$( %宛先~window, `messageerror$et, `MessageEvent$I ) — 次のように初期化して ⇒# `origin$m 属性 ~SET %生成元, `source$m 属性 ~SET %~source ◎ fire an event named messageerror at targetWindow, using MessageEvent, with the origin attribute initialized to origin and the source attribute initialized to source,\
      2. ~RET ◎ and then return.
    5. %~message~clone ~LET %逆直列化-~record.`Deserialized^sl ◎ Let messageClone be deserializeRecord.[[Deserialized]].
    6. %新~port~list ~LET %逆直列化-~record.`TransferredValues^sl 内に在る すべての `MessagePort$I ~objからなる,同順の新たな`凍結d配列$ ◎ Let newPorts be a new frozen array consisting of all MessagePort objects in deserializeRecord.[[TransferredValues]], if any, maintaining their relative order.
    7. `~eventを発火する$( %宛先~window, `message$et, `MessageEvent$I ) — 次のように初期化して ⇒# `origin$m 属性 ~SET %生成元, `source$m 属性 ~SET %~source, `data$m 属性 ~SET %~message~clone, `ports$m 属性 ~SET %新~port~list ◎ Fire an event named message at targetWindow, using MessageEvent, with the origin attribute initialized to origin, the source attribute initialized to source, the data attribute initialized to messageClone, and the ports attribute initialized to newPorts.
`Window$I の `~postMessageO(message, options)@m ~method~手続きは ⇒ `~windowに~messageを投函する手続き$( コレ, %message, %options ) ◎ The Window interface's postMessage(message, options) method steps are to run the window post message steps given this, message, and options.
`Window$I の `postMessage(message, targetOrigin, transfer)@m ~method~手続きは ⇒ `~windowに~messageを投函する手続き$( コレ, %message, «[ "`targetOrigin$m" → %targetOrigin, "`transfer$m" → %transfer ]» ) ◎ The Window interface's postMessage(message, targetOrigin, transfer) method steps are to run the window post message steps given this, message, and «[ "targetOrigin" → targetOrigin, "transfer" → transfer ]».

9.4. ~channel~message法

`MessagePort^CTX

9.4.1. 序論

◎非規範的

`~channel~message法$ 【 `channel messaging^en ( “~channelを介した~messageの送信-法” )】 を利用すれば、 作者は,独立な~code片どうし (例えば,異なる`閲覧~文脈$内で走っているもの) を直に通信させれる。 ◎ To enable independent pieces of code (e.g. running in different browsing contexts) to communicate directly, authors can use channel messaging.

この仕組みにおける通信~channelは、[ 両端に~portを伴う,二重化された~pipe ]として実装される。 一方の~portに送信される~messageは,他方の~portに送達され、 逆も同様になる。 各~messageは、 走っている`~task$を中断したり阻むことなく,~DOM~eventとして送達される。 ◎ Communication channels in this mechanism are implemented as two-ways pipes, with a port at each end. Messages sent in one port are delivered at the other port, and vice-versa. Messages are delivered as DOM events, without interrupting or blocking running tasks.

接続( “連絡された” 2 個の~port)を作成するためには、 `new MessageChannel()$m 構築子を~callする: ◎ To create a connection (two "entangled" ports), the MessageChannel() constructor is called:

var %channel = new MessageChannel();

一方の~portは 局所~portとして保たれ、 他方の~portは ~remote~codeへ送信される — 例えば `window.postMessage()$m を利用して: ◎ One of the ports is kept as the local port, and the other port is sent to the remote code, e.g. using postMessage():

%otherWindow.postMessage('hello', 'https://example.com', [%channel.port2]);

~messageを送信するためには、 局所~port上の ``postMessage()$m ~methodを利用する: ◎ To send messages, the postMessage() method on the port is used:

%channel.port1.postMessage('hello');

~messageを受信するためには、 `message$et ~eventを~listenする: ◎ To receive messages, one listens to message events:

%channel.port1.onmessage = handleMessage;
function handleMessage(%event) {
  /* 
~messageは %event の`data$m 属性~内にある
◎
message is in event.data
 */
  // ...
}

~portに送信する~dataは、 有構造~dataも可能である。 例えば,次では、 文字列たちが成す配列が `MessagePort$I に渡される: ◎ Data sent on a port can be structured data; for example here an array of strings is passed on a MessagePort:

%channel.port1.postMessage(['hello', 'world']);
9.4.1.1. 例
◎非規範的

この例では、 2 つの~JS~libraryが `MessagePort$I を利用して互いに接続される。 これにより,~libraryは、 ~APIを何ら変更することなく,後で[ `~worker$ ~obj/異なる~frame ]内に~hostすることも可能になる。 ◎ In this example, two JavaScript libraries are connected to each other using MessagePorts. This allows the libraries to later be hosted in different frames, or in Worker objects, without any change to the APIs.

<script src="contacts.js"></script> <!-- 
%contacts ~objを公開する
◎
exposes a contacts object
 -->
<script src="compose-mail.js"></script> <!-- 
%composer ~objを公開する
◎
exposes a composer object
 -->
<script>
 var %channel = new MessageChannel();
 %composer.addContactsProvider(%channel.port1);
 %contacts.registerConsumer(%channel.port2);
</script>

`addContactsProvider()^c 関数の実装は、 次の様になる: ◎ Here's what the "addContactsProvider()" function's implementation could look like:

function addContactsProvider(%port) {
  %port.onmessage = function (%event) {
    switch (%event.data.messageType) {
      case 'search-result': handleSearchResult(%event.data.results); break;
      case 'search-done': handleSearchDone(); break;
      case 'search-error': handleSearchError(%event.data.message); break;
      // ...
    }
  };
};

あるいは、 次に従って実装することもできる: ◎ Alternatively, it could be implemented as follows:

function addContactsProvider(%port) {
  %port.addEventListener('message', function (%event) {
    if (%event.data.messageType == 'search-result')
      handleSearchResult(%event.data.results);
  });
  %port.addEventListener('message', function (%event) {
    if (%event.data.messageType == 'search-done')
      handleSearchDone();
  });
  %port.addEventListener('message', function (%event) {
    if (%event.data.messageType == 'search-error')
      handleSearchError(%event.data.message);
  });
  // ...
  %port.start();
};

上の 2 つの~codeにおける~~主な違いは、 `addEventListener()$m を利用した場合, ``start()$m ~methodも呼出す必要がある点にある。 ``onmessage$m を利用した場合、 暗黙的に ``start()$m も~callされる。 ◎ The key difference is that when using addEventListener(), the start() method must also be invoked. When using onmessage, the call to start() is implied.

``start()$m ~methodは、 明示的に~callされようが, ( ``onmessage$m を設定することにより)暗黙的に~callされようが, ~messageの~flowを開始する。 その前の初期~時においては、 ~message~portに投函された~messageは — ~scriptが自身による~handlerを設定しておく機会cを得る前に,どこかで落とされないよう — 静止される。 ◎ The start() method, whether called explicitly or implicitly (by setting onmessage), starts the flow of messages: messages posted on message ports are initially paused, so that they don't get dropped on the floor before the script has had a chance to set up its handlers.

9.4.1.2. ~web上の~obj能力~modelの基礎としての~port
◎非規範的

~portは、[ ~system内の他の動作者に,制限された能力を公開する仕方 ]と捉えることもできる (~obj能力~model的イミで 【参考:`~obj能力~model@https://en.wikipedia.org/wiki/Object-capability_model$】 )。 これは、 弱い能力~systemにも,強い能力~modelにもなり得る。 弱い能力~systemにおける~portは、 単に同じ生成元の中の簡便な~modelとして利用される。 強い能力~systemにおける~portは、 ある生成元に属する %提供者 ( `provider^en )により, 別の生成元に属する %消費者 ( `consumer^en )向けに[[ %提供者 に効果を及ぼせる/ %提供者 からの情報を得せる ]ための唯一の仕組み ]として提供される。 ◎ Ports can be viewed as a way to expose limited capabilities (in the object-capability model sense) to other actors in the system. This can either be a weak capability system, where the ports are merely used as a convenient model within a particular origin, or as a strong capability model, where they are provided by one origin provider as the only mechanism by which another origin consumer can effect change in or obtain information from provider.

例えば、 ある %~social~site の~pageが, 次のような 2 個の `iframe$e を埋込んでいる状況を考える: ◎ For example, consider a situation in which a social web site embeds\

  • %提供者~frame は、 ( %~social~site とは別の生成元に属する) %提供者 — ここでは,利用者の~address-bookを提供している~serviceとする — からの内容を含んでいる ◎ in one iframe the user's email contacts provider (an address book site, from a second origin), and\
  • %消費者~frame は、 (また別の生成元に属する) %消費者 — 例えば,ある~game~siteなど — からの内容を含んでいる ◎ in a second iframe a game (from a third origin).\

%~social~site ~page, および %消費者~frame 内からは、 %提供者~frame の内側にあるものには~accessできない — これら二者が %提供者~frame の内側に何か及ぼせるのは、 次に限られる: ◎ The outer social site and the game in the second iframe cannot access anything inside the first iframe; together they can only:

  • %提供者~frame を[ %提供者~frame の~URLと`素片$urlだけ異なる`~URL$ ]へ`~navigate$する — %提供者~frame 内の`~window$は `hashchange$et ~eventを受信することになる。 ◎ Navigate the iframe to a new URL, such as the same URL but with a different fragment, causing the Window in the iframe to receive a hashchange event.
  • %提供者~frame を~resizeする — %提供者~frame 内の`~window$は `resize$et ~eventを受信することになる。 ◎ Resize the iframe, causing the Window in the iframe to receive a resize event.
  • `window.postMessage()$m ~APIを利用して, %提供者~frame 内の`~window$へ `message$et ~eventを送信する。 ◎ Send a message event to the Window in the iframe using the window.postMessage() API.

%提供者 は、 これらのうち,特に 3 番目の手法 — `message$et ~event — を利用して,[ 他の生成元から~accessできるような,利用者の~address-bookを操作するための~API ]を提供する。 例えば, ~message "add-contact: Guillaume Tell <tell@pomme.example.net>" に対し、 それが与える連絡先 — 個人名, ~email~address — を利用者の~address-bookに追加することにより,応答することもできる。 ◎ The contacts provider can use these methods, most particularly the third one, to provide an API that can be accessed by other origins to manipulate the user's address book. For example, it could respond to a message "add-contact Guillaume Tell <tell@pomme.example.net>" by adding the given person and email address to the user's address book.

~web上の どの~siteも利用者の~address-bookを操作できては困るので、 %提供者 は,一定の信用-済み~site — 当の %~social~site など — に限って これを許容するであろう。 ◎ To avoid any site on the web being able to manipulate the user's contacts, the contacts provider might only allow certain trusted sites, such as the social site, to do this.

ここで、 %消費者 は,利用者の~address-bookに連絡先(例えば、~gameの対戦相手のそれ)を追加したいと求めていて、 %~social~site は,自らに利するため それを許容する用意があるとする — それは,本質的には、 %提供者 が %~social~site と信用-を “共有すること” に等しい。 これを行う仕方にはいくつかあり、 最も単純なのは, %~social~site が %消費者 ~siteと %提供者 ~siteの間の~messageを代理することであろう。 しかしながら、 この解決策には難点がある: ◎ Now suppose the game wanted to add a contact to the user's address book, and that the social site was willing to allow it to do so on its behalf, essentially "sharing" the trust that the contacts provider had with the social site. There are several ways it could do this; most simply, it could just proxy messages between the game site and the contacts site. However, this solution has a number of difficulties:\

  • %~social~site は、[ %消費者 ~siteが特権を濫用しないこと ]を完全に信用するか,あるいは 許容したくない要請 (連絡先を[ 複数個~追加する/読取る/削除する ]など) ではないことを確かめるため, 各~要請を検証yすることが要求される。 ◎ it requires the social site to either completely trust the game site not to abuse the privilege, or it requires that the social site verify each request to make sure it's not a request that it doesn't want to allow (such as adding multiple contacts, reading the contacts, or deleting them);\
  • 他にもいくつかの %消費者 が居て,同時に %提供者 とヤリトリすることもあり得る場合、 複階性が増す。 ◎ it also requires some additional complexity if there's ever the possibility of multiple games simultaneously trying to interact with the contacts provider.

~message~channelと `MessagePort$I ~objを利用すれば、 これらの問題をすべて消し去れる。 %消費者 が連絡先を追加したいと求める旨を %~social~site に伝えたとき、 %~social~site は、連絡先を追加することではなく,[ 1 個の連絡先を追加する能力 ]について, %提供者 に依頼できる。 それに対し, %提供者 は、 `MessagePort$I ~objの~pairを作成して, その片方を %~social~site に返信する。 %~social~site は、 受信したそれを %消費者 に回送する。 それにより, %消費者 と %提供者 は直に接続されることになり、 %提供者 は, “1 個の連絡先を追加する” 要請のみ尊守すればよいことを知る。 言い換えれば、 %消費者 には, 1 個の連絡先を追加する能力が是認されたことになる。 ◎ Using message channels and MessagePort objects, however, all of these problems can go away. When the game tells the social site that it wants to add a contact, the social site can ask the contacts provider not for it to add a contact, but for the capability to add a single contact. The contacts provider then creates a pair of MessagePort objects, and sends one of them back to the social site, who forwards it on to the game. The game and the contacts provider then have a direct connection, and the contacts provider knows to only honor a single "add contact" request, nothing else. In other words, the game has been granted the capability to add a single contact.

9.4.1.3. ~service実装を抽象-化する基礎としての~port
◎非規範的

前~節からの例を引き継いで、 特に, %提供者 側を考える。 初期~実装では,単純に[ ~serviceの `iframe$e 内で `XMLHttpRequest$I ~objを利用していた ]が、 ~serviceの発展に伴い,[ 単独の `WebSocket$I 接続を備える`共用~worker$の利用 ]に代えたいと求めることもあろう。 ◎ Continuing the example from the previous section, consider the contacts provider in particular. While an initial implementation might have simply used XMLHttpRequest objects in the service's iframe, an evolution of the service might instead want to use a shared worker with a single WebSocket connection.

初期~設計の段階で, `MessagePort$I ~objを[ 能力を是認する/単に複数の独立な~sessionを同時に許容する ]ために利用していたなら、 ~service実装は,~APIに全く手を加えずに[ 各 `iframe$e ごとに `XMLHttpRequest$I を用いる~model ]から[ `WebSocket$I を共有する~model ]へ切替えれるようになる — ~service提供者~側のすべての~portは、 ~APIの利用者にまったく影響することなく,共用~workerに回送できる。 ◎ If the initial design used MessagePort objects to grant capabilities, or even just to allow multiple simultaneous independent sessions, the service implementation can switch from the XMLHttpRequests-in-each-iframe model to the shared-WebSocket model without changing the API at all: the ports on the service provider side can all be forwarded to the shared worker without it affecting the users of the API in the slightest.

9.4.2. ~message~channel

[Exposed=(Window,Worker)]
interface `MessageChannel@I {
  ``MessageChannel$mc();

  readonly attribute `MessagePort$I `port1$m;
  readonly attribute `MessagePort$I `port2$m;
};
%channel = `new MessageChannel()$m
2 個の新たな `MessagePort$I ~objが伴われた,新たな `MessageChannel$I ~objを返す。 ◎ Returns a new MessageChannel object with two new MessagePort objects.
%channel.`port1$m
1 個目の `MessagePort$I ~objを返す。 ◎ Returns the first MessagePort object.
%channel.`port2$m
2 個目の `MessagePort$I ~objを返す。 ◎ Returns the second MessagePort object.

各 `MessageChannel$I ~objには、 `~port 1@, `~port 2@ が結付けられる — どちらも `MessagePort$I ~objを与える。 ◎ A MessageChannel object has an associated port 1 and an associated port 2, both MessagePort objects.

`new MessageChannel()@m 構築子~手続きは: ◎ The new MessageChannel() constructor steps are:

  1. コレの`~port 1$ ~SET コレに`関連な~realm$に属する`新たな$ `MessagePort$I ◎ Set this's port 1 to a new MessagePort in this's relevant realm.
  2. コレの`~port 2$ ~SET コレに`関連な~realm$に属する`新たな$ `MessagePort$I ◎ Set this's port 2 to a new MessagePort in this's relevant realm.
  3. `~portを連絡する$( コレの`~port 1$, コレの`~port 2$ ) ◎ Entangle this's port 1 and this's port 2.
`port1@m 取得子~手続きは ⇒ ~RET コレの`~port 1$ ◎ The port1 getter steps are to return this's port 1.
`port2@m 取得子~手続きは ⇒ ~RET コレの`~port 2$ ◎ The port2 getter steps are to return this's port 2.

9.4.3. ~message~port

各~channelは、 2 個の~message~portを持つ。 一方の~portから送信された~dataは,他方の~portに受信され、 逆も同様になる。 ◎ Each channel has two message ports. Data sent through one port is received by the other port, and vice versa.

[Exposed=(Window,Worker,AudioWorklet), `Transferable$]
interface `MessagePort@I : `EventTarget$I {
  undefined ``postMessage$m(any %message, sequence<`object$> %transfer);
  undefined ``~postMessageO$m(any %message, optional `StructuredSerializeOptions$I %options = {});
  undefined ``start$m();
  undefined ``close$m();

  // event handlers
  attribute `EventHandler$I ``onmessage$m;
  attribute `EventHandler$I ``onmessageerror$m;
  attribute `EventHandler$I ``onclose$m;
};

dictionary `StructuredSerializeOptions@I {
  sequence<`object$> `transfer@m = [];
};
%port.``postMessage( message, transfer)$m【! [, transfer]】
%port.``~postMessageO(message [, options])$m
~channelを通して~messageを投函する。 [ %transfer /[ %options の `transfer$m ~member ]]内に~listされた~objは、 ~cloneされるのみならず転送される — すなわち、 送信-側からは,それ以降 それらを利用できなくなる。 ◎ Posts a message through the channel. Objects listed in transfer are transferred, not just cloned, meaning that they are no longer usable on the sending side.
次の場合は `DataCloneError$E が投出される ⇒ %transfer が 同じ[ ~obj/~port ]を重複して包含する場合 / %message を~cloneできなかった場合 ◎ Throws a "DataCloneError" DOMException if transfer contains duplicate objects or port, or if message could not be cloned.
%port.``start()$m
この~portに受信される/された~messageを配送させ始める。 ◎ Begins dispatching messages received on the port.
%port.``close()$m
この~portを切断する。 以降、 この~portは作動中でなくなる。 ◎ Disconnects the port, so that it is no longer active.

各 `MessagePort$I ~objは、 別のそれと連絡され得る(その関係性は対称になる)。

【 `port1$m, `port2$m のどちらを手元において もう片方を転送しようがかまわない。 】

各 `MessagePort$I ~objは、 次に挙げるものを持つ:

`~port~message~queue@
`~task~source$†。 初期~時には空とする。 `~port~message~queue$は、 初期~時には不能化されており,ある時点で可能化され得る。 可能化された後,再び不能化されることは決してない (~queue~内の~messageたちは,[ 別の~queueへ移動される/すべて除去される ]こともあるが、 それは,不能化されるのとほぼ同じ効果になる)。
【† すなわち,個々の`~port~message~queue$は、 `~task~queue$であると同時に,独立な~task~sourceを成す。 】
`搬送-済みか@
初期~時には ~F をとるモノトスル
◎ Each MessagePort object can be entangled with another (a symmetric relationship). Each MessagePort object also has a task source called the port message queue, initially empty. A port message queue can be enabled or disabled, and is initially disabled. Once enabled, a port can never be disabled again (though messages in the queue can get moved to another queue or removed altogether, which has much the same effect). A MessagePort also has a has been shipped flag, which must initially be false.

ある~port %P の`~port~message~queue$ %Q が可能化されたときは、 `~event~loop$は, %Q をその`~task~source$の一つとして利用する†モノトスル。 【†すなわち、 %Q を成す各~taskを~event~loopの中で走らすことになる。】 %P に`関連な大域~obj$は`~window$である場合、 %Q に~queueされた`~task$の`文書$tKは, %P に`関連な大域~obj$に`結付けられた文書$になるモノトスル。 ◎ When a port's port message queue is enabled, the event loop must use it as one of its task sources. When a port's relevant global object is a Window, all tasks queued on its port message queue must be associated with the port's relevant global object's associated Document.

注記: [ 当の文書は`全部的に作動中$である ]が[ 【~port用に登録された】すべての~event~listenerは、 `全部的に作動中$でない文書の文脈~内で作成されていた ]場合、 ~queueされた各~messageは,それらの文書が再び`全部的に作動中$に[ ならない限り/なるまでは ],受信されないことになる。 ◎ If the document is fully active, but the event listeners were all created in the context of documents that are not fully active, then the messages will not be received unless and until the documents become fully active again.

各 `~event~loop$は、 `未搬送な~port~message~queue@ と呼ばれる`~task~source$を持つ。 これは, “仮想の†” ~queueであり、[ 下の条件を満たす各 `MessagePort$I %P の`~port~message~queue$ ]内の~taskすべてを,~queueされた順序††で包含しているかのように動作するモノトスル — ~taskが`未搬送な~port~message~queue$から除去されるときは、 代わりに,それが実際に属する`~port~message~queue$から除去するモノトスル。

ここで、 各 %P は ~AND↓ を満たすとする:

  • %P の`搬送-済みか$ ~EQ ~F
  • %P の`~port~message~queue$は可能化されている
  • %P に`関連な~agent$の`~event~loop$aG ~EQ 当の`~event~loop$

【† “仮想の” — すなわち、 いくつかの~queueを包装するだけの,それ自身は~~実体を持たない~queue。 】【†† 異なる`~port~message~queue$に属する~taskどうしの, `未搬送な~port~message~queue$の中での順序がどう定義されるのかは、 明確に述べられていない(単に時系列順?)。 】

◎ Each event loop has a task source called the unshipped port message queue. This is a virtual task source: it must act as if it contained the tasks of each port message queue of each MessagePort whose has been shipped flag is false, whose port message queue is enabled, and whose relevant agent's event loop is that event loop, in the order in which they were added to their respective task source. When a task would be removed from the unshipped port message queue, it must instead be removed from its port message queue.

[ `MessagePort$I の`搬送-済みか$ ~EQ ~F ]の下では、 その`~port~message~queue$は,`~event~loop$の目的においては無視するモノトスル (代わりに,`未搬送な~port~message~queue$が利用される)。 ◎ When a MessagePort's has been shipped flag is false, its port message queue must be ignored for the purposes of the event loop. (The unshipped port message queue is used instead.)

注記: `MessagePort$I ~obj %P の`搬送-済みか$は、[ %P, %P の相手~側~port, %P の~clone元~obj ]のいずれかが,転送されるか, すでにされている ]ときに ~T にされる。 %P の`搬送-済みか$が ~T にされて以降は、 %P の`~port~message~queue$は first-class `~task~source$ 【すなわち, “通常の,独立な” ~task~source】 として動作し,`未搬送な~port~message~queue$には影響しなくなる 【その一部を成さなくなる】。 ◎ The has been shipped flag is set to true when a port, its twin, or the object it was cloned from, is or has been transferred. When a MessagePort's has been shipped flag is true, its port message queue acts as a first-class task source, unaffected to any unshipped port message queue.

~UAは, `~portを連絡する@ ときは、所与の 2 個の `MessagePort$I ~obj ( %A, %B ) に対し,次の手続きを走らすモノトスル: ◎ When the user agent is to entangle two MessagePort objects, it must run the following steps:

  1. ~EACH( %P ~IN { %A, %B } ) に対し ⇒ ~IF[ %P に連絡された別の `MessagePort$I ~obj %Q がある ] ⇒ %P と %Q との連絡を断つ ◎ If one of the ports is already entangled, then disentangle it and the port that it was entangled with.

    注記: %P, %Q が,ある `MessageChannel$I ~obj %C の 2 個の~portを成していた場合、 %C は もはや実際の~channelを表現しなくなる — それ以降、 %P と %Q が連絡されることはない。 ◎ If those two previously entangled ports were the two ports of a MessageChannel object, then that MessageChannel object no longer represents an actual channel: the two ports in that object are no longer entangled.

  2. %A, %B を,ある新たな~channelの 2 個の部位を形成するように結付けて連絡する(その~channelを表現する `MessageChannel$I ~objは,まだない) ◎ Associate the two ports to be entangled, so that they form the two parts of a new channel. (There is no MessageChannel object that represents this channel.)

    この時点で %A, %B は 互いに連絡されたことになる。 ◎ Two ports A and B that have gone through this step are now said to be entangled; one is entangled to the other, and vice versa.

    注記: この仕様は,この処理nを瞬時に生じるもの( `instantaneous^en )として述べるが、 実装は,~messageを渡すことを介して実装する見込みが高い。 要は、 他の~algoと同じく, “単に” [ その最終-結果が — ~black-box的イミで — 仕様が定めるものと判別-不能 ]であればよい。 ◎ While this specification describes this process as instantaneous, implementations are more likely to implement it via message passing. As with all algorithms, the key is "merely" that the end result be indistinguishable, in a black-box sense, from the specification.

`~portの連絡を断つ@ 手続きは、 所与の ( 連絡を断つことを起動した `MessagePort$I %起動元~port ) に対し: ◎ The disentangle steps, given a MessagePort initiatorPort which initiates disentangling, are as follows:

  1. %相手~port ~LET %起動元~port に連絡されている `MessagePort$I ◎ Let otherPort be the MessagePort which initiatorPort was entangled with.
  2. ~Assert: %相手~port は存在する。 ◎ Assert: otherPort exists.
  3. %起動元~port と %相手~port の連絡を断つ — それらが、 もはや互いに連絡されなくなり,結付けられなくなるよう。 ◎ Disentangle initiatorPort and otherPort, so that they are no longer entangled or associated with each other.
  4. `~eventを発火する$( %相手~port, `close$et ) ◎ Fire an event named close at otherPort.

注記: `close$et ~eventは、 次に挙げる事例で発火される — ~portが明示的に~closeされた場合のみならず: ◎ The close event will be fired even if the port is not explicitly closed. The cases where this event is dispatched are:

  • ``close()$m ~methodが~callされたとき ◎ the close() method was called;
  • 当の`文書$が`破壊された@~HTMLlifecycle#destroy-a-document$とき ◎ the Document was destroyed; or
  • 当の `MessagePort$I が`~garbage収集された@#ports-and-garbage-collection$とき ◎ the MessagePort was garbage collected.

~eventは %相手~port にしか配送されない — 上で述べたとおり、 ~closeを明示的に誘発したのは %起動元~port であるか, %起動元~port の`文書$は もはや存在しないか, %起動元~port は すでに~garbage収集されたので。 ◎ We only dispatch the event on otherPort because initiatorPort explicitly triggered the close, its Document no longer exists, or it was already garbage collected, as described above.


`MessagePort$I ~objは`転送-可能$である: ◎ MessagePort objects are transferable objects.\

  • その`転送-手続き$は、所与の ( %値, %~data保持体 ) に対し,次を走らす: ◎ Their transfer steps, given value and dataHolder, are:

    1. %値 の`搬送-済みか$ ~SET ~T ◎ Set value's has been shipped flag to true.
    2. %~data保持体.`PortMessageQueue^sl ~SET %値 の`~port~message~queue$ ◎ Set dataHolder.[[PortMessageQueue]] to value's port message queue.
    3. ~IF[ ある別~port %~remote~port が %値 に連絡されている ]: ◎ If value is entangled with another port remotePort, then:

      1. %~remote~port の`搬送-済みか$ ~SET ~T ◎ Set remotePort's has been shipped flag to true.
      2. %~data保持体.`RemotePort^sl ~SET %~remote~port ◎ Set dataHolder.[[RemotePort]] to remotePort.

    4. ~ELSE ⇒ %~data保持体.`RemotePort^sl ~SET ~NULL ◎ Otherwise, set dataHolder.[[RemotePort]] to null.

  • その`転送-受信-時の手続き$は、所与の ( %~data保持体, %値 ) に対し,次を走らす: ◎ Their transfer-receiving steps, given dataHolder and value, are:

    1. %値 の`搬送-済みか$ ~SET ~T ◎ Set value's has been shipped flag to true.
    2. %~data保持体.`PortMessageQueue^sl を成す ~EACH( `message$et ~eventを発火する`~task$ %~task ) に対し:

      1. %~task を %値 の`~port~message~queue$に移動する — この`~port~message~queue$は、 (初期~時の)不能化~状態のまま変えないとする
      2. ~IF[ %値 に`関連な大域~obj$は`~window$である ] ⇒ %~task の`文書$tK ~SET %値 に`関連な大域~obj$に`結付けられた文書$
      ◎ Move all the tasks that are to fire message events in dataHolder.[[PortMessageQueue]] to the port message queue of value, if any,\ leaving value's port message queue in its initial disabled state, and,\ if value's relevant global object is a Window, associating the moved tasks with value's relevant global object's associated Document.
    3. ~IF[ %~data保持体.`RemotePort^sl ~NEQ ~NULL ] ⇒ `~portを連絡する$( %~data保持体.`RemotePort^sl, %値 ) ⇒ (これは、 元の転送された~portと %~data保持体.`RemotePort^sl との連絡を断つことになる。) ◎ If dataHolder.[[RemotePort]] is not null, then entangle dataHolder.[[RemotePort]] and value. (This will disentangle dataHolder.[[RemotePort]] from the original port that was transferred.)

`~message~portに~messageを投函する手続き@ は、所与の ( %~source~port, %宛先~port, %~message, %options ) に対し,次に従う: ◎ The message port post message steps, given sourcePort, targetPort, message and options are as follows:

  1. %transfer ~LET %options[ "`transfer$m" ] ◎ Let transfer be options["transfer"].
  2. ~IF[ %~source~port ~IN %transfer ] ⇒ ~THROW `DataCloneError$E ◎ If transfer contains sourcePort, then throw a "DataCloneError" DOMException.
  3. %破棄予定か ~LET ~F ◎ Let doomed be false.
  4. ~IF[ %宛先~port ~NEQ ~NULL ]~AND[ %宛先~port ~IN %transfer ]: ◎ If targetPort is not null and transfer contains targetPort, then\

    1. %破棄予定か ~SET ~T ◎ set doomed to true and\
    2. 任意選択で ⇒ [ %宛先~port が自身に向けて投函された結果,通信~channelは失われること ]を,~UAの開発者~consoleに報告する ◎ optionally report to a developer console that the target port was posted to itself, causing the communication channel to be lost.
  5. %転送-を伴う直列化-結果 ~LET `StructuredSerializeWithTransfer$jA( %message, %transfer ) (例外投出あり) ◎ Let serializeWithTransferResult be StructuredSerializeWithTransfer(message, transfer). Rethrow any exceptions.
  6. ~IF[ %宛先~port ~EQ ~NULL ]~OR[ %破棄予定か ~EQ ~T ] ⇒ ~RET ◎ If targetPort is null, or if doomed is true, then return.
  7. 次の手続きを走らす`~task$を %宛先~port の`~port~message~queue$に追加する: ◎ Add a task that runs the following steps to the port message queue of targetPort:

    1. %最終-宛先~port ~LET この~taskが見出される`~port~message~queue$を持つ `MessagePort$I ~obj ◎ Let finalTargetPort be the MessagePort in whose port message queue the task now finds itself.

      これは %宛先~port と異なり得る — %宛先~port 自身が転送されるに伴い,その~taskすべても移動された場合には。 ◎ This can be different from targetPort, if targetPort itself was transferred and thus all its tasks moved along with it.

    2. %宛先~realm ~LET %最終-宛先~port に`関連な~realm$ ◎ Let targetRealm be finalTargetPort's relevant realm.
    3. %逆直列化-~record ~LET `StructuredDeserializeWithTransfer$jA( %転送-を伴う直列化-結果, %宛先~realm ) ◎ Let deserializeRecord be StructuredDeserializeWithTransfer(serializeWithTransferResult, targetRealm).

      ここで例外が投出されたときは、 ~catchして: ◎ If this throws an exception, catch it,\

      1. `~eventを発火する$( %最終-宛先~port, `messageerror$et, `MessageEvent$I ) ◎ fire an event named messageerror at finalTargetPort, using MessageEvent,\
      2. ~RET ◎ and then return.
    4. %~message~clone ~LET %逆直列化-~record.`Deserialized^sl ◎ Let messageClone be deserializeRecord.[[Deserialized]].
    5. %新~port~list ~LET %逆直列化-~record.`TransferredValues^sl 内に在る すべての `MessagePort$I ~objからなる,同順の新たな`凍結d配列$ ◎ Let newPorts be a new frozen array consisting of all MessagePort objects in deserializeRecord.[[TransferredValues]], if any, maintaining their relative order.
    6. `~eventを発火する$( %最終-宛先~port, `message$et, `MessageEvent$I ) — 次のように初期化して ⇒# `data$m 属性 ~SET %~message~clone, `ports$m 属性 ~SET %新~port~list ◎ Fire an event named message at finalTargetPort, using MessageEvent, with the data attribute initialized to messageClone and the ports attribute initialized to newPorts.

``~postMessageO(message, options)@m ~method~手続きは: ◎ The postMessage(message, options) method steps are:

  1. %宛先~port ~LET [ コレに連絡されている~portは在るならば それ / ~ELSE_ ~NULL ] ◎ Let targetPort be the port with which this is entangled, if any; otherwise let it be null.
  2. `~message~portに~messageを投函する手続き$( コレ, %宛先~port, %message, %options ) ◎ Run the message port post message steps providing this, targetPort, message and options.

``postMessage(message, transfer)@m ~method~手続きは: ◎ The postMessage(message, transfer) method steps are:

  1. %宛先~port ~LET [ コレに連絡されている~portは在るならば それ / ~ELSE_ ~NULL ] ◎ Let targetPort be the port with which this is entangled, if any; otherwise let it be null.
  2. `~message~portに~messageを投函する手続き$( コレ, %宛先~port, %message, «[ "`transfer$m" → %transfer ]» ) ◎ Let options be «[ "transfer" → transfer ]». ◎ Run the message port post message steps providing this, targetPort, message and options.
``start()@m ~method~手続きは ⇒ コレの`~port~message~queue$を — まだ可能化されていなければ — 可能化する ◎ The start() method steps are to enable this's port message queue, if it is not already enabled.

``close()@m ~method~手続きは: ◎ The close() method steps are:

  1. コレの `Detached$sl 内部~slot ~SET ~T ◎ Set this's [[Detached]] internal slot value to true.
  2. ~IF[ コレには別~portが連絡されている ] ⇒ `~portの連絡を断つ$( コレ ) ◎ If this is entangled, disentangle it.

`MessagePort$I ~interfaceを実装している すべての~objは、[ 以下に挙げる`~event~handler$, および対応する`~event~handler~event型$ ]を`~event~handler~IDL属性$として~supportするモノトスル: ◎ The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the MessagePort interface:

`~event~handler$ `~event~handler~event型$
``onmessage@m `message$et
``onmessageerror@m `messageerror$et
``onclose@m `close$et【!*】

%P の`~port~message~queue$は、 `MessagePort$I ~obj %P の ``onmessage$m ~IDL属性が初回に設定された時点で, %P の ``start()$m ~methodが~callされたかのように可能化されるモノトスル。 ◎ The first time a MessagePort object's onmessage IDL attribute is set, the port's port message queue must be enabled, as if the start() method had been called.

9.4.4. ~portと~garbage収集

`MessagePort$I ~obj %O が~garbage収集されたときは、 %O が他と連絡されている場合には,次を遂行するモノトスル ⇒ `~portの連絡を断つ$( %O ) ◎ When a MessagePort object o is garbage collected, if o is entangled, then the user agent must disentangle o.

`MessagePort$I ~obj %O が他と連絡されていて,[ `message$et / `messageerror$et ]~event~listenerが登録されている間は、 ~UAは,[ %O に連絡された `MessagePort$I ~objは %O への強い参照を有する ]かのように動作するモノトスル。 ◎ When a MessagePort object o is entangled and message or messageerror event listener is registered, user agents must act as if o's entangled MessagePort object has a strong reference to o.

更には, `MessagePort$I ~obj %O は、 ~OR↓ が満たされている間は,~garbage収集されないモノトスル: ◎ Furthermore, a MessagePort object must not be garbage collected\

  • ある`~task~queue$内の ある`~task$が、 %O に向けて配送される~eventを参照している ◎ while there exists an event referenced by a task in a task queue that is to be dispatched on that MessagePort object, or\
  • %O の`~port~message~queue$は、 空でない, かつ 可能化されている ◎ while the MessagePort object's port message queue is enabled and not empty.

注記: したがって、 ~message~portは,[ 受信して~event~listenerをあてがった後は,放置する ]こともできる — その~event~listenerが~messageを受信できる限り,~channelは保守される。 ◎ Thus, a message port can be received, given an event listener, and then forgotten, and so long as that event listener could receive a message, the channel will be maintained.

無論,これが当の~channelの両~側に生じた場合、 両~portとも~garbage収集され得る — それらは、 互いに強い参照があるとしても, 生きた~codeからは到達-不能になるので。 しかしながら、 ~message~portに処理待ち~messageがある場合,~garbage収集されない。 ◎ Of course, if this was to occur on both sides of the channel, then both ports could be garbage collected, since they would not be reachable from live code, despite having a strong reference to each other. However, if a message port has a pending message, it is not garbage collected.

注記: 作者には、 `MessagePort$I ~objを明示的に~closeして,それらの連絡を断つことが強く奨励される — そうすれば、 それらの資源を収集し直せるようになる。 多数の `MessagePort$I ~objを作成して,それらを~closeすることなく破棄することは、 ~memory利用量が一時に跳ね上がり得る — ~garbage収集は、 とりわけ[ `MessagePort$I に対する~garbage収集に~cross-processの協調も孕まれ得る所 ]では,即座に遂行されるとは限らないので。 ◎ Authors are strongly encouraged to explicitly close MessagePort objects to disentangle them, so that their resources can be recollected. Creating many MessagePort objects and discarding them without closing them can lead to high transient memory usage since garbage collection is not necessarily performed promptly, especially for MessagePorts where garbage collection can involve cross-process coordination.

9.5. 他の閲覧~文脈への~broadcast法

`BroadcastChannel^CTX

ときには、 同じ`生成元$に属する複数の~pageどうしが[ 同じ~UA内で同じ利用者から開かれていているが, 互いに関係しない異なる`閲覧~文脈$内にあるとき ]でも,互いに通知を送信しあう必要が生じることもある。 例えば ⇒ “利用者がこっちに~log-inしたから、 そっちでも資格証を再度~検査してくれ” ◎ Pages on a single origin opened by the same user in the same user agent but in different unrelated browsing contexts sometimes need to send notifications to each other, for example "hey, the user logged in over here, check your credentials again".

もっと手の込んだ事例においては、 `共用~worker$が最も適切な解決策になる — 例えば ⇒# 共有されている状態の~lockingを管理する / ~serverと複数の局所~clientとの間で 資源の同期法を管理する / `WebSocket$I 接続を~remote~hostと共有する / 等々 ◎ For elaborate cases, e.g. to manage locking of shared state, to manage synchronization of resources between a server and multiple local clients, to share a WebSocket connection with a remote host, and so forth, shared workers are the most appropriate solution.

共用~workerでは大げさになるような単純な事例では、 作者は,この節に述べる 単純な[ ~channelに基づく~broadcastの仕組み ]を利用できる。 ◎ For simple cases, though, where a shared worker would be an unreasonable overhead, authors can use the simple channel-based broadcast mechanism described in this section.

[Exposed=(Window,Worker)]
interface `BroadcastChannel@I : `EventTarget$I {
  ``BroadcastChannel$mc(DOMString %name);
  readonly attribute DOMString ``name$m;
  undefined ``postMessage$m(any %message);
  undefined ``close$m();
  attribute `EventHandler$I ``onmessage$m;
  attribute `EventHandler$I ``onmessageerror$m;
};
%broadcastChannel = `new BroadcastChannel(name)$m
~channel名 %name の~channelを介して~messageを[ 送信できる/受信できる ]ような,新たな `BroadcastChannel$I ~objを返す。 ◎ Returns a new BroadcastChannel object via which messages for the given channel name can be sent and received.
%broadcastChannel.``name$m
(構築子に渡された)~channel名を返す。 ◎ Returns the channel name (as passed to the constructor).
%broadcastChannel.``postMessage(message)$m
所与の~messageを,この~channelに設定しておかれた 他の `BroadcastChannel$I ~objへ送信する。 ~messageは、 入子な~objや配列など,有構造~dataも可能である。 ◎ Sends the given message to other BroadcastChannel objects set up for this channel. Messages can be structured objects, e.g. nested objects and arrays.
%broadcastChannel.``close()$m
`BroadcastChannel$I ~objを~closeして,~garbage収集に委ねる。 ◎ Closes the BroadcastChannel object, opening it up to garbage collection.

`BroadcastChannel$I ~objは、 次に挙げるものを持つ:

`~channel名@
共有する通信~channelを識別する文字列。
`~closeされたか@
真偽値 — ~T ならば、 通信は~closeされたことを指示する。
◎ A BroadcastChannel object has a channel name and a closed flag.
`new BroadcastChannel(name)@m 構築子~手続きは ⇒ コレの ⇒# `~channel名$ ~SET %name, `~closeされたか$ ~SET ~F ◎ The new BroadcastChannel(name) constructor steps are: • Set this's channel name to name. • Set this's closed flag to false.
``name@m 取得子~手続きは ⇒ ~RET コレの`~channel名$ ◎ The name getter steps are to return this's channel name.

`BroadcastChannel$I ~objが `~message法に適格@ であるとは、 それに`関連な大域~obj$が次のいずれかであることをいう: ◎ A BroadcastChannel object is said to be eligible for messaging when its relevant global object is either:

  • 次を満たす `Window$I ~objである ⇒ それに`結付けられた文書$は`全部的に作動中$である ◎ a Window object whose associated Document is fully active, or
  • 次を満たす `WorkerGlobalScope$I ~objである ⇒ [ その`~close中か$wG ~EQ ~F ]~AND[ その`~worker$は`休止-可能$でない ] ◎ a WorkerGlobalScope object whose closing flag is false and whose worker is not a suspendable worker.

``postMessage(message)@m ~method~手続きは: ◎ The postMessage(message) method steps are:

  1. ~IF[ コレは`~message法に適格$でない ] ⇒ ~RET ◎ If this is not eligible for messaging, then return.
  2. ~IF[ コレの`~closeされたか$ ~EQ ~T ] ⇒ ~THROW `InvalidStateError$E ◎ If this's closed flag is true, then throw an "InvalidStateError" DOMException.
  3. %直列形 ~LET `StructuredSerialize$jA( %~message, %宛先~realm ) (例外投出あり) ◎ Let serialized be StructuredSerialize(message). Rethrow any exceptions.
  4. %~source生成元 ~LET コレに`関連な設定群~obj$の`生成元$enV ◎ Let sourceOrigin be this's relevant settings object's origin.
  5. %~source~storage~key ~LET `非~storage目的~用に~storage~keyを得する$( コレに`関連な設定群~obj$ ) ◎ Let sourceStorageKey be the result of running obtain a storage key for non-storage purposes with this's relevant settings object.
  6. %行先~list ~LET ~AND↓ を満たす `BroadcastChannel$I ~obj %O たちが成す~list: ◎ Let destinations be a list of BroadcastChannel objects that match the following criteria:

    • %O は`~message法に適格$である ◎ They are eligible for messaging.
    • ( 次の結果, %~source~storage~key ) は`同等な~storage~key$である ⇒ `非~storage目的~用に~storage~keyを得する$( %O に`関連な設定群~obj$ ) ◎ The result of running obtain a storage key for non-storage purposes with their relevant settings object equals sourceStorageKey.
    • %O の`~channel名$ ~EQ コレの`~channel名$ ◎ Their channel name is this's channel name.
  7. %行先~list からコレを除去する ◎ Remove source from destinations.
  8. %行先~list を成す `BroadcastChannel$I たちを,次が満たされるように~sortする ⇒ `関連な~agent$が同じものどうしは、 旧いものから,作成された順に並ぶ (これは、 完全な順序付けは定義しない。 ~UAは、 この拘束の下で,`実装定義$な方式で更に~sortしてもヨイ。) ◎ Sort destinations such that all BroadcastChannel objects whose relevant agents are the same are sorted in creation order, oldest first. (This does not define a complete ordering. Within this constraint, user agents may sort the list in any implementation-defined manner.)
  9. %行先~list を成す ~EACH( %行先 ) に対し ⇒ `大域~taskを~queueする$( `~DOM操作~task~source$, %行先 に`関連な大域~obj$, 次の手続き ) ◎ For each destination in destinations, queue a global task on the DOM manipulation task source given destination's relevant global object to perform the following steps:

    手続きは: ◎ ↑

    1. ~IF[ %行先 の`~closeされたか$ ~EQ ~F ] ⇒ ~RET ◎ If destination's closed flag is true, then abort these steps.
    2. %宛先~realm ~LET %行先 に`関連な~realm$ ◎ Let targetRealm be destination's relevant realm.
    3. %~data ~LET `StructuredDeserialize$jA( %直列形, %宛先~realm ) ◎ Let data be StructuredDeserialize(serialized, targetRealm).

      ここで例外が投出されたときは、 ~catchして: ◎ If this throws an exception, catch it,\

      1. `~eventを発火する$( %行先, `messageerror$et, `MessageEvent$I ) — 次のように初期化して ⇒# `origin$m 属性 ~SET `生成元を直列化する$( %~source生成元 ) ◎ fire an event named messageerror at destination, using MessageEvent, with the origin attribute initialized to the serialization of sourceOrigin,\
      2. ~RET ◎ and then abort these steps.
    4. `~eventを発火する$( %行先, `message$et, `MessageEvent$I ) — 次のように初期化して ⇒# `data$m 属性 ~SET %~data, `origin$m 属性 ~SET `生成元を直列化する$( %~source生成元 ) ◎ Fire an event named message at destination, using MessageEvent, with the data attribute initialized to data and the origin attribute initialized to the serialization of sourceOrigin.

`BroadcastChannel$I ~obj %O に対しては、 次が満たされている間は, %O に`関連な大域~obj$から %O への強い参照があるモノトスル ⇒ [ %O の`~closeされたか$ ~EQ ~F ]~AND[ %O 向けの[ `message$et / `messageerror$et ]~event用に登録されている~event~listenerがある ] ◎ While a BroadcastChannel object whose closed flag is false has an event listener registered for message or messageerror events, there must be a strong reference from the BroadcastChannel object's relevant global object to the BroadcastChannel object itself.

``close()@m ~method~手続きは ⇒ コレの`~closeされたか$ ~SET ~T ◎ The close() method steps are to set this's closed flag to true.

注記: 作者には、 `BroadcastChannel$I ~objが不要になり次第,[ ~UAが~garbage収集できるよう,明示的に~closeする ]ことが強く奨励される。 多数の `BroadcastChannel$I ~objを作成して, ~event~listenerを伴わせたまま ~closeすることなく破棄した場合、 目に見える~memory漏洩に至りかねない — それらの~objは、 ~event~listenerがある限り (または、それらが属する[ ~page/~worker ]が~closeされるまで), 生き続けようとするので。 ◎ Authors are strongly encouraged to explicitly close BroadcastChannel objects when they are no longer needed, so that they can be garbage collected. Creating many BroadcastChannel objects and discarding them while leaving them with an event listener and without closing them can lead to an apparent memory leak, since the objects will continue to live for as long as they have an event listener (or until their page or worker is closed).


`BroadcastChannel$I ~interfaceを実装している~すべての~objは、[ 以下に挙げる`~event~handler$, および対応する`~event~handler~event型$ ]を`~event~handler~IDL属性$として~supportするモノトスル: ◎ The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the BroadcastChannel interface:

`~event~handler$ `~event~handler~event型$
``onmessage@m `message$et
``onmessageerror@m `messageerror$et

ある~pageが利用者が,いつ~log-outしたか知りたいと求めているとする — 同じ~siteに属する別の~UItabの~pageから利用者がそうしたときでも: ◎ Suppose a page wants to know when the user logs out, even when the user does so from another tab at the same site:

var %authChannel = new BroadcastChannel('auth');
%authChannel.onmessage = function (%event) {
  if (%event.data == 'logout')
    showLogout();
}

function logoutRequested() {
  /* 
利用者から~log-outを請われたとき,~callされる
◎
called when the user asks us to log them out
 */
  doLogout();
  showLogout();
  %authChannel.postMessage('logout');
}

function doLogout() {
  /* 
利用者は実際に~log-outした(例: ~cookieを~clearするなど)
◎
actually log the user out (e.g. clearing cookies)
 */
  // ...
}

function showLogout() {
  /* 
~log-outしたことを指示するように,~UIを更新する
◎
update the UI to indicate we're logged out
 */
  // ...
}