HTML — web worker

10. ~web~worker

10.1. 序論

10.1.1. 視野

◎非規範的

この仕様は、 他の~UI~scriptから独立に,~backgroundで~scriptを走らすための~APIを定義する。 ◎ This specification defines an API for running scripts in the background independently of any user interface scripts.

それは、 次を許容する ⇒ ~clickその他 利用者-ヤリトリに応答する~scriptから中断されることなく, 長期に渡り~scriptを走らせる — すなわち、 ~pageを即応可能に保ちながら,長い~taskを実行する。 ◎ This allows for long-running scripts that are not interrupted by scripts that respond to clicks or other user interactions, and allows long tasks to be executed without yielding to keep the page responsive.

~worker(これらの~background~scriptの ここでの名称)は、 比較的 重いので,多数の同時利用は意図されていない。 例えば、 画像~内に幾千万ある画素ごとに異なる~workerを立上げるのは不適切である。 下の例に~workerの適切な利用を示す: ◎ Workers (as these background scripts are called herein) are relatively heavy-weight, and are not intended to be used in large numbers. For example, it would be inappropriate to launch one worker for each pixel of a four megapixel image. The examples below show some appropriate uses of workers.

一般に,~workerは長時間居残り続けるので、 開始時の処理能~cost, および~instanceごとの~memory~costは,高くつくものと予期されている。 ◎ Generally, workers are expected to be long-lived, have a high start-up performance cost, and a high per-instance memory cost.

10.1.2. 例

◎非規範的

~workerには様々な利用がある。 以下の各~下位節に,その利用を示す。 ◎ There are a variety of uses that workers can be put to. The following subsections show various examples of this use.

10.1.2.1. ~backgroundで数値計算し続ける~worker
◎非規範的

~workerの最も単純な利用は、 ~UIを中断せずに計算量の大きな仕事を遂行するものである。 ◎ The simplest use of workers is for performing a computationally expensive task without interrupting the user interface.

この例では、 ~main文書が~workerを生み出して, (素朴な)素数の~~計算を行い, 見つかった最新の素数を漸進的に表示し続ける。 ◎ In this example, the main document spawns a worker to (naïvely) compute prime numbers, and progressively displays the most recently found prime number.

~main~pageは次で与えられる: ◎ The main page is as follows:

<!DOCTYPE HTML>
<html>
 <head>
  <meta charset="utf-8">
  <title>~worker例: 単-~coreによる~~計算</title>
 </head>
 <body>
  <p>これまでに見つかった最~大の素数は:<output id="result"></output></p>

<script>
   var %worker = new Worker('worker.js');
   %worker.onmessage = function (%event) {
     document.getElementById('result').textContent = %event.data;
   };
</script>

 </body>
</html>

`new Worker()$m 構築子の~callにより,~workerが作成され、[ その~workerを表現し, その~workerと通信する, `Worker$I ~obj ]が返される。 ~objの `onmessage$m ~event~handlerには、 ~workerから~messageを受信する~codeを入れられる。 ◎ The Worker() constructor call creates a worker and returns a Worker object representing that worker, which is used to communicate with the worker. That object's onmessage event handler allows the code to receive messages from the worker.

~worker自身は次で与えられる: ◎ The worker itself is as follows:

var %n = 1;
search: while (true) {
  %n += 1;
  for (var %i = 2; %i <= Math.sqrt(%n); %i += 1)
    if (%n % %i == 0)
     continue search;
  /* 
素数~~発見!
◎
found a prime!
 */
  postMessage(%n);
}

【 いきなり `postMessage()$m が大域~関数として登場している所からも推察されるように、 ちょうど通常時における~scriptの `Window^I ~objにあたる, ~worker用の~script実行~環境を与える大域~obj (`§ 大域~scope@#the-global-scope$)が, (~workerを生み出した側の実行~環境とは別に) 存在している、 と考えれば,この仕様の残りの部分も理解し易い。 】

この~codeは、 単純な,最適化されていない,素数の探索~routineである。 `postMessage()$m が、 見つかった素数を~messageにして~pageに返信する~methodである。 ◎ The bulk of this code is simply an unoptimized search for a prime number. The postMessage() method is used to send a message back to the page when a prime is found.

`この例を~onlineで見る@~DEMO/primes/page.html$ ◎ View this example online.

10.1.2.2. ~JS~moduleを~workerとして利用する
◎非規範的

これまでの どの例も`古典~script$を走らす~workerを示してきたが、 ~workerは,`~module~script$を利用して~instance化することもできる — これには、 通例的に,次に挙げる便益がある:

  • ~JS `import^c 文を利用して他の~moduleを~importする能
  • 既定で~strict~modeになる
  • ~workerの大域~scopeを汚さない,~top-levelの宣言
◎ All of our examples so far show workers that run classic scripts. Workers can instead be instantiated using module scripts, which have the usual benefits: the ability to use the JavaScript import statement to import other modules; strict mode by default; and top-level declarations not polluting the worker's global scope.

`import^c 文が可用になったことに伴い、 `importScripts()$m ~methodは,~module~workerの内側では自動的に失敗することになる。 ◎ As the import statement is available, the importScripts() method will automatically fail inside module workers.

この例では、 ~main文書が[ ~main~threadの外で画像~操作を行う~worker ]を利用する。 それは、 別の~moduleから利用される~filterを~importする。 ◎ In this example, the main document uses a worker to do off-main-thread image manipulation. It imports the filters used from another module.

~main~pageは: ◎ The main page is as follows:

<!DOCTYPE html>
<meta charset="utf-8">
<title>~worker例: 画像を復号する</title>

<p>
  <label>
    復号する画像の URL を入れてください
    <input type="url" id="image-url" list="image-list">
    <datalist id="image-list">
      <option value="https://html.spec.whatwg.org/images/drawImage.png">
      <option value="https://html.spec.whatwg.org/images/robots.jpeg">
      <option value="https://html.spec.whatwg.org/images/arcTo2.png">
    </datalist>
  </label>
</p>

<p>
  <label>
    適用する~filterを選んでください
    <select id="filter">
      <option value="none">none</option>
      <option value="grayscale">grayscale</option>
      <option value="brighten">brighten by 20%</option>
    </select>
  </label>
</p>

<div id="output"></div>

<script type="module">
  const %worker = new Worker("worker.js", { type: "module" });
  %worker.onmessage = receiveFromWorker;

  const %url = document.querySelector("#image-url");
  const %filter = document.querySelector("#filter");
  const %output = document.querySelector("#output");

  %url.oninput = updateImage;
  %filter.oninput = sendToWorker;

  let %imageData, %context;

  function updateImage() {
    const %img = new Image();
    %img.src = %url.value;

    %img.onload = () => {

      const %canvas = document.createElement("canvas");
      %canvas.width = %img.width;
      %canvas.height = %img.height;

      %context = %canvas.getContext("2d");
      %context.drawImage(%img, 0, 0);
      %imageData = %context.getImageData(0, 0, %canvas.width, %canvas.height);

      sendToWorker();
      %output.replaceChildren(%canvas);
    };
  }

  function sendToWorker() {
    %worker.postMessage({ %imageData, filter: %filter.value });
  }

  function receiveFromWorker(%e) {
    %context.putImageData(%e.data, 0, 0);
  }
</script>

~worker~fileは: ◎ The worker file is then:

import * as filters from "./filters.js";

self.onmessage = %e => {
  const { %imageData, %filter } = %e.data;
  filters[%filter](%imageData);
  self.postMessage(%imageData, [%imageData.data.buffer]);
};

これは、 次の~file `filters.js^c を~importする: ◎ Which imports the file filters.js:

export function none() {}

export function grayscale({ data: %d }) {
  for (let %i = 0; %i < %d.length; %i += 4) {
    const [%r, %g, %b] = [%d[%i], %d[%i + 1], %d[%i + 2]];
    /* 
RGB に対する CIE 輝度
— ヒトの目は 赤, 青 に鈍感なので,それらを減衰する
◎
CIE luminance for the RGB
— The human eye is bad at seeing red and blue, so we de-emphasize them.
 */
    %d[%i] = %d[%i + 1] = %d[%i + 2] = 0.2126 * %r + 0.7152 * %g + 0.0722 * %b;
  }
};

export function brighten({ data: %d }) {
  for (let %i = 0; %i < %d.length; ++%i) {
    %d[%i] *= 1.2;
  }
};

`この例を~onlineで見る@~DEMO/modules/page.html$ ◎ View this example online.

10.1.2.3. 共用~worker序論
◎非規範的

この節では、 Hello World の例を利用して,共用~workerを導入する。 共用~workerにおいては、 各~workerが複数の接続を有し得るので,少し異なる~APIが利用される。 ◎ This section introduces shared workers using a Hello World example. Shared workers use slightly different APIs, since each worker can have multiple connections.

この最初の例では、[ ~pageから~workerに どう接続するか ]および[ 接続-時に ~workerが~pageに向けて~messageを どう返信するか ]を示す。 受信された~messageは、 ~logに表示される。 ◎ This first example shows how you connect to a worker and how a worker can send a message back to the page when it connects to it. Received messages are displayed in a log.

~HTML~pageをここに示す: ◎ Here is the HTML page:

<!DOCTYPE HTML>
<meta charset="utf-8">
<title>共用~worker: ~demo 1</title>
<pre id="log">Log:</pre>

<script>
  var %worker = new SharedWorker('test.js');
  var %log = document.getElementById('log');
  %worker.port.onmessage = function(%e) { /* 
%worker.onmessage ではないことに注意
◎
note: not worker.onmessage!
 */
    %log.textContent += '\n' + %e.data;
  }
</script>

~JS~workerは次になる: ◎ Here is the JavaScript worker:

onconnect = function(%e) {
  var %port = %e.ports[0];
  %port.postMessage('Hello World!');
}

【 `onconnect^m の名が~~示唆するように、 接続が確立され次第,~workerの大域~scopeに属する `onconnect()^m が呼出される。 】

`この例を~onlineで見る@~DEMO/shared/001/test.html$ ◎ View this example online.


次の例は、 2 つの変更により,最初のものを拡張する: まず, ~messageは`~event~handler~IDL属性$の代わりに `addEventListener()$m を利用して受信される。 次に,~messageは ~workerに向けて送信され, それに対し~workerが別の~messageを返信するようにしている。 受信された~messageは再び~logに表示される。 ◎ This second example extends the first one by changing two things: first, messages are received using addEventListener() instead of an event handler IDL attribute, and second, a message is sent to the worker, causing the worker to send another message in return. Received messages are again displayed in a log.

~HTML~pageは: ◎ Here is the HTML page:

<!DOCTYPE HTML>
<meta charset="utf-8">
<title>共用~worker: ~demo 2</title>
<pre id="log">Log:</pre>

<script>
  var %worker = new SharedWorker('test.js');
  var %log = document.getElementById('log');
  %worker.port.addEventListener('message', function(%e) {
    %log.textContent += '\n' + %e.data;
  }, false);
  %worker.port.start(); /* 
注記: `addEventListener()^m を利用した場合はこれが必要になる
◎
note: need this when using addEventListener
 */
  %worker.port.postMessage('ping');
</script>

~JS~workerは: ◎ Here is the JavaScript worker:

onconnect = function(%e) {
  var %port = %e.ports[0];
  %port.postMessage('Hello World!');
  %port.onmessage = function(%e) {
    %port.postMessage('pong'); /* 
%e.ports[0].postMessage ではないことに注意
◎
not e.ports[0].postMessage!
 */
    /* 
%e.target.postMessage('pong'); でもいける
◎
e.target.postMessage('pong'); would work also
 */
  }
}

`この例を~onlineで見る@~DEMO/shared/002/test.html$ ◎ View this example online.


最後の例は、 2 つの~pageから同じ~workerに接続させる方法を示す。 この例では, 2 番目の~pageは 単に最初の~pageの `iframe$e に入れられているが、 同じ原理は,[ 別々な`~top-level辿可能$に属する まったく別々な~page ]であっても通用する。 ◎ Finally, the example is extended to show how two pages can connect to the same worker; in this case, the second page is merely in an iframe on the first page, but the same principle would apply to an entirely separate page in a separate top-level traversable.

外縁~HTML~page: ◎ Here is the outer HTML page:

<!DOCTYPE HTML>
<meta charset="utf-8">
<title>共用~worker: ~demo 3</title>
<pre id="log">Log:</pre>

<script>
  var %worker = new SharedWorker('test.js');
  var %log = document.getElementById('log');
  %worker.port.addEventListener('message', function(%e) {
    %log.textContent += '\n' + %e.data;
  }, false);
  %worker.port.start();
  %worker.port.postMessage('ping');
</script>

<iframe src="inner.html"></iframe>

内縁~HTML~page: ◎ Here is the inner HTML page:

<!DOCTYPE HTML>
<meta charset="utf-8">
<title>共用~worker: ~demo 3 inner frame</title>
<pre id=log>Inner log:</pre>

<script>
  var %worker = new SharedWorker('test.js');
  var %log = document.getElementById('log');
  %worker.port.onmessage = function(%e) {
   %log.textContent += '\n' + %e.data;
  }
</script>

~JS~workerは: ◎ Here is the JavaScript worker:

var %count = 0;
onconnect = function(%e) {
  %count += 1;
  var %port = %e.ports[0];
  %port.postMessage('Hello World! You are connection #' + %count);
  %port.onmessage = function(%e) {
    %port.postMessage('pong');
  }
}

`この例を~onlineで見る@~DEMO/shared/003/test.html$ ◎ View this example online.

10.1.2.4. 共用~workerの利用による状態の共有-
◎非規範的

次の例では、 同じマップを~~表示する複数の~window(~viewer)を開けるようになっている。 すべての~windowが同じマップ情報を共有し、 単独の~workerが すべての~viewerを協調する。 各~viewerの中では,他と独立にマップ内を動き回れ、 いずれかの~viewerにてマップ内に何らかの~dataが置かれたときは, すべての~viewerが更新される。 ◎ In this example, multiple windows (viewers) can be opened that are all viewing the same map. All the windows share the same map information, with a single worker coordinating all the viewers. Each viewer can move around independently, but if they set any data on the map, all the viewers are updated.

~main~pageは、 興味を引くものではなく, ~viewerを開く仕方を供するものでしかない: ◎ The main page isn't interesting, it merely provides a way to open the viewers:

<!DOCTYPE HTML>
<html>
 <head>
  <meta charset="utf-8">
  <title>~worker例: Multiviewer</title>

<script>
   function openViewer() {
     window.open('viewer.html');
   }
</script>

 </head>
 <body>
  <p><button type=button onclick="openViewer()">新たな~viewerを開く</button></p>
  <p>各~viewerは新たな~windowを開きます。好きなだけ,いくつでも~viewerを開けます。それらはすべて同じ~dataを~~表示します。</p>
 </body>
</html>

より深く関わるのは、 ~viewerである: ◎ The viewer is more involved:

<!DOCTYPE HTML>
<html>
 <head>
  <meta charset="utf-8">
  <title>~worker例: Multiviewer ~viewer</title>

<script>
   var %worker = new SharedWorker('worker.js', 'core');

   /* 
環境設定
◎
CONFIGURATION
 */
   function configure(%event) {
     if (%event.data.substr(0, 4) != 'cfg ') return;
     var %name = %event.data.substr(4).split(' ', 1)[0];
     /* 
名前が %name であることを示すために表示を更新する
◎
update display to mention our name is name
 */
     document.getElementsByTagName('h1')[0].textContent += ' ' + %name;
     /* 
この~listenerはもう不要
◎
no longer need this listener
 */
     %worker.port.removeEventListener('message', configure, false);
   }
   %worker.port.addEventListener('message', configure, false);

   /* 
マップ
◎
MAP
 */
   function paintMap(%event) {
     if (%event.data.substr(0, 4) != 'map ') return;
     var %data = %event.data.substr(4).split(',');
     /* 
%data[0] .. %data[8] の各升を表示する
◎
display tiles data[0] .. data[8]
 */
     var %canvas = document.getElementById('map');
     var %context = %canvas.getContext('2d');
     for (var %y = 0; %y < 3; %y += 1) {
       for (var %x = 0; %x < 3; %x += 1) {
         var %tile = data[%y * 3 + %x];
         if (%tile == '0')
           %context.fillStyle = 'green';
         else 
           %context.fillStyle = 'maroon';
         %context.fillRect(x * 50, y * 50, 50, 50);
       }
     }
   }
   %worker.port.addEventListener('message', paintMap, false);

   /* 
~public~chat
◎
PUBLIC CHAT
 */
   function updatePublicChat(%event) {
     if (%event.data.substr(0, 4) != 'txt ') return;
     var %name = %event.data.substr(4).split(' ', 1)[0];
     var %message = %event.data.substr(4 + %name.length + 1);
     /* 
~public~chatに "<%name> %message" を表示する
◎
display "<name> message" in public chat
 */
     var %public = document.getElementById('public');
     var %p = document.createElement('p');
     var %n = document.createElement('button');
     %n.textContent = '<' + %name + '> ';
     %n.onclick = function () { %worker.port.postMessage('msg ' + %name); };
     %p.appendChild(%n);
     var %m = document.createElement('span');
     %m.textContent = %message;
     %p.appendChild(%m);
     %public.appendChild(%p);
   }
   %worker.port.addEventListener('message', updatePublicChat, false);

   /* 
~private~chat
◎
PRIVATE CHAT
 */
   function startPrivateChat(%event) {
     if (%event.data.substr(0, 4) != 'msg ') return;
     var %name = %event.data.substr(4).split(' ', 1)[0];
     var %port = %event.ports[0];
     /* 
~private~chat~UIを表示する
◎
display a private chat UI
 */
     var %ul = document.getElementById('private');
     var %li = document.createElement('li');
     var %h3 = document.createElement('h3');
     %h3.textContent = 'Private chat with ' + %name;
     %li.appendChild(%h3);
     var %div = document.createElement('div');
     var %addMessage = function(%name, %message) {
       var %p = document.createElement('p');
       var %n = document.createElement('strong');
       %n.textContent = '<' + %name + '> ';
       %p.appendChild(%n);
       var %t = document.createElement('span');
       %t.textContent = %message;
       %p.appendChild(%t);
       %div.appendChild(%p);
     };
     %port.onmessage = function (%event) {
       addMessage(%name, %event.data);
     };
     %li.appendChild(%div);
     var %form = document.createElement('form');
     var %p = document.createElement('p');
     var %input = document.createElement('input');
     %input.size = 50;
     %p.appendChild(%input);
     %p.appendChild(document.createTextNode(' '));
     var %button = document.createElement('button');
     %button.textContent = 'Post';
     %p.appendChild(%button);
     %form.onsubmit = function () {
       %port.postMessage(%input.value);
       addMessage('me', %input.value);
       %input.value = '';
       return false;
     };
     %form.appendChild(%p);
     %li.appendChild(%form);
     %ul.appendChild(%li);
   }
   %worker.port.addEventListener('message', startPrivateChat, false);

   %worker.port.start();
</script>

 </head>
 <body>
  <h1>Viewer</h1>
  <h2>Map</h2>
  <p><canvas id="map" height=150 width=150></canvas></p>
  <p>
   <button type=button onclick="%worker.port.postMessage('mov left')"
   >Left</button>
   <button type=button onclick="%worker.port.postMessage('mov up')"
   >Up</button>
   <button type=button onclick="%worker.port.postMessage('mov down')"
   >Down</button>
   <button type=button onclick="%worker.port.postMessage('mov right')"
   >Right</button>
   <button type=button onclick="%worker.port.postMessage('set 0')"
   >Set 0</button>
   <button type=button onclick="%worker.port.postMessage('set 1')"
   >Set 1</button>
  </p>
  <h2>Public Chat</h2>
  <div id="public"></div>
  <form onsubmit="%worker.port.postMessage('txt ' + %message.value);
    %message.value = ''; return false;"
  >
   <p>
    <input type="text" name="message" size="50">
    <button>Post</button>
   </p>
  </form>
  <h2>Private Chat</h2>
  <ul id="private"></ul>
 </body>
</html>

~viewerの書かれ方には、 着目すべき点がいくつかある。 ◎ There are several key things worth noting about the way the viewer is written.

複数の~listener: この~codeは、 1 個の~message処理~関数の代わりに, 複数の~event~listenerを付け加えている — それぞれが~messageに関連するかどうか~~簡単な検査を遂行するような。 この例では,さほど大きな相違は生じないが、 幾人かの作者~達が協同する中で, ~workerとの通信に単独の~portの利用が求まれる~~状況においても、 すべての変更を単独の~event取扱い関数に加えることなく, 独立な~codeでそれが可能になる。 ◎ Multiple listeners. Instead of a single message processing function, the code here attaches multiple event listeners, each one performing a quick check to see if it is relevant for the message. In this example it doesn't make much difference, but if multiple authors wanted to collaborate using a single port to communicate with a worker, it would allow for independent code instead of changes having to all be made to a single event handling function.

このような仕方で~event~listenerを登録した場合、 この例の `configure()^c ~methodのように, 事を終えた~listenerを~~個別的に未登録にすることも可能になる。 ◎ Registering event listeners in this way also allows you to unregister specific listeners when you are done with them, as is done with the configure() method in this example.

最後に,~worker: ◎ Finally, the worker:

var %nextName = 0;
function getNextName() {
  /* 
もっと親しみ易い名前にすることもできたが、
今の所は,ただの番号。
◎
this could use more friendly names but for now just return a number
 */
  return %nextName++;
}

var %map = [
 [0, 0, 0, 0, 0, 0, 0],
 [1, 1, 0, 1, 0, 1, 1],
 [0, 1, 0, 1, 0, 0, 0],
 [0, 1, 0, 1, 0, 1, 1],
 [0, 0, 0, 1, 0, 0, 0],
 [1, 0, 0, 1, 1, 1, 1],
 [1, 1, 0, 1, 1, 0, 1],
];

function wrapX(%x) {
  if (%x < 0) return wrapX(%x + %map[0].length);
  if (%x >= %map[0].length) return wrapX(%x - %map[0].length);
  return %x;
}

function wrapY(%y) {
  if (%y < 0) return wrapY(%y + %map.length);
  if (%y >= %map[0].length) return wrapY(%y - %map.length);
  return %y;
}

function wrap(%val, %min, %max) {
  if (%val < %min)
    return %val + (%max - %min) + 1;
  if (%val > %max)
    return %val - (%max - %min) - 1;
  return %val;
}

function sendMapData(%viewer) {
  var %data = '';
  for (var %y = %viewer.y - 1; y <= %viewer.y + 1; %y += 1) {
    for (var %x = %viewer.x - 1; %x <= %viewer.x + 1; %x += 1) {
      if (%data != '')
        %data += ',';
      %data += %map[wrap(%y, 0, %map[0].length-1)][wrap(%x, 0, %map.length-1)];
    }
  }
  %viewer.port.postMessage('map ' + %data);
}

var %viewers = {};
onconnect = function (%event) {
  var %name = getNextName();
  %event.ports[0]._data = { port: event.ports[0], name: %name, x: 0, y: 0, };
  %viewers[%name] = %event.ports[0]._data;
  %event.ports[0].postMessage('cfg ' + %name);
  %event.ports[0].onmessage = getMessage;
  sendMapData(event.ports[0]._data);
};

function getMessage(%event) {
  switch (%event.data.substr(0, 4)) {
    case 'mov ':
      var %direction = %event.data.substr(4);
      var %dx = 0;
      var %dy = 0;
      switch (%direction) {
        case 'up': %dy = -1; break;
        case 'down': %dy = 1; break;
        case 'left': %dx = -1; break;
        case 'right': %dx = 1; break;
      }
      %event.target._data.x = wrapX(%event.target._data.x + %dx);
      %event.target._data.y = wrapY(%event.target._data.y + %dy);
      sendMapData(%event.target._data);
      break;
    case 'set ':
      var %value = %event.data.substr(4);
      map[%event.target._data.y][%event.target._data.x] = %value;
      for (var %viewer in %viewers)
        sendMapData(%viewers[%viewer]);
      break;
    case 'txt ':
      var %name = %event.target._data.name;
      var %message = %event.data.substr(4);
      for (var %viewer in %viewers)
        %viewers[%viewer].port.postMessage('txt ' + %name + ' ' + %message);
      break;
    case 'msg ':
      var %party1 = %event.target._data;
      var %party2 = %viewers[%event.data.substr(4).split(' ', 1)[0]];
      if (%party2) {
        var %channel = new MessageChannel();
        %party1.port.postMessage('msg ' + %party2.name, [%channel.port1]);
        %party2.port.postMessage('msg ' + %party1.name, [%channel.port2]);
      }
      break;
  }
}

複数の~pageへの接続-法: この~scriptは、 複数の接続を~listenするために, `onconnect$m ~event~listenerを利用している。 ◎ Connecting to multiple pages. The script uses the onconnect event listener to listen for multiple connections.

直通~channel: ~workerが, 一方の~viewerから他方の~viewerを~~指名する `msg^l ~messageを受信したときには、 両者の間に直な接続が設定しておかれる — ~workerがすべての~messageを代理しなくとも、 両~viewerは直に通信できる。 ◎ Direct channels. When the worker receives a "msg" message from one viewer naming another viewer, it sets up a direct connection between the two, so that the two viewers can communicate directly without the worker having to proxy all the messages.

`この例を~onlineで見る@~DEMO/multiviewer/page.html$ ◎ View this example online.

10.1.2.5. 委任
◎非規範的

複-~core~CPUの普及に伴い、 計算量の大きな仕事を複数の~workerに分業させて, より良い処理能が得されるようになっている。 この例では、 1 〜 10,000,000 に付番された計算量の大きな仕事を 10 等分して, 10 個の下位workerに遂行させる。 ◎ With multicore CPUs becoming prevalent, one way to obtain better performance is to split computationally expensive tasks amongst multiple workers. In this example, a computationally expensive task that is to be performed for every number from 1 to 10,000,000 is farmed out to ten subworkers.

~main~pageは、 単に結果を報告する: ◎ The main page is as follows, it just reports the result:

<!DOCTYPE HTML>
<html>
 <head>
  <meta charset="utf-8">
  <title>~worker例: 複-~coreによる~~計算</title>
 </head>
 <body>
  <p>Result: <output id="result"></output></p>

<script>
   var %worker = new Worker('worker.js');
   %worker.onmessage = function (%event) {
     document.getElementById('result').textContent = %event.data;
   };
</script>

 </body>
</html>

~worker自身は: ◎ The worker itself is as follows:

/* 
設定
◎
settings
 */
var %num_workers = 10;
var %items_per_worker = 1000000;

/* 
~workerを開始する
◎
start the workers
 */
var %result = 0;
var %pending_workers = %num_workers;
for (var %i = 0; %i < %num_workers; %i += 1) {
  var %worker = new Worker('core.js');
  %worker.postMessage(%i * %items_per_worker);
  %worker.postMessage((%i+1) * %items_per_worker);
  %worker.onmessage = storeResult;
}

/* 
結果を取扱う
◎
handle the results
 */
function storeResult(%event) {
  %result += 1*%event.data;
  %pending_workers -= 1;
  if (%pending_workers <= 0)
    postMessage(%result); /* 
完成!
◎
finished!
 */
}

それは、 一連の下位workerを開始させる~loopと, 各 下位workerから返される応答を待機する~handlerからなる。 ◎ It consists of a loop to start the subworkers, and then a handler that waits for all the subworkers to respond.

下位workerの実装は: ◎ The subworkers are implemented as follows:

var %start;
onmessage = getStart;
function getStart(%event) {
  %start = 1*%event.data;
  onmessage = getEnd;
}

var %end;
function getEnd(%event) {
  %end = 1*%event.data;
  onmessage = null;
  work();
}

function work() {
  var %result = 0;
  for (var %i = %start; i < %end; %i += 1) {
    /* 
何か複階的な計算がここで遂行される
◎
perform some complex calculation here
 */
    %result += 1;
  }
  postMessage(%result);
  close();
}

これらはそれぞれ、 2 度の~eventで 2 個の番号を受信して, それにより指定される付番~範囲の~~計算を遂行して, 結果を親に報告する。 ◎ They receive two numbers in two events, perform the computation for the range of numbers thus specified, and then report the result back to the parent.

`この例を~onlineで見る@~DEMO/multicore/page.html$ ◎ View this example online.

10.1.2.6. ~libraryを供するとき
◎非規範的

次の 3 種の~taskを供する,ある暗号化~libraryが可用であるとする: ◎ Suppose that a cryptography library is made available that provides three tasks:

( 公開鍵, 私用鍵 ) ~pairを生成する: ◎ Generate a public/private key pair
渡された~portに, 2 個の~message — 最初に公開鍵,次に私用鍵 — を送信する。 ◎ Takes a port, on which it will send two messages, first the public key and then the private key.
所与の ( 平文, 公開鍵 ) から,対応する暗号文を返す: ◎ Given a plaintext and a public key, return the corresponding ciphertext
渡された~portに,任意個数の~message — 最初に公開鍵,以降は平文 — を送信する。 各 平文は、 暗号化されてから暗号文と同じ~channelに送信される。 内容を暗号化し終えたなら,~portを~closeできる。 ◎ Takes a port, to which any number of messages can be sent, the first giving the public key, and the remainder giving the plaintext, each of which is encrypted and then sent on that same channel as the ciphertext. The user can close the port when it is done encrypting content.
所与の ( 暗号文, 私用鍵 ) 対応する平文を返す ◎ Given a ciphertext and a private key, return the corresponding plaintext
渡された~portに,任意個数の~message — 最初に私用鍵,以降は暗号文 — を送信する。 各 暗号文は、 復号化されてから平文と同じ~channelに送信される。 内容を復号化し終えたなら,~portを~closeできる。 ◎ Takes a port, to which any number of messages can be sent, the first giving the private key, and the remainder giving the ciphertext, each of which is decrypted and then sent on that same channel as the plaintext. The user can close the port when it is done decrypting content.

~library自身は: ◎ The library itself is as follows:

function handleMessage(%e) {
  if (%e.data == "genkeys")
    genkeys(%e.ports[0]);
  else if (%e.data == "encrypt")
    encrypt(%e.ports[0]);
  else if (%e.data == "decrypt")
    decrypt(%e.ports[0]);
}

function genkeys(%p) {
  var %keys = _generateKeyPair();
  %p.postMessage(%keys[0]);
  %p.postMessage(%keys[1]);
}

function encrypt(%p) {
  var %key, %state = 0;
  %p.onmessage = function (%e) {
    if (%state == 0) {
      %key = %e.data;
      %state = 1;
    } else {
      %p.postMessage(_encrypt(%key, %e.data));
    }
  };
}

function decrypt(%p) {
  var %key, %state = 0;
  %p.onmessage = function (%e) {
    if (%state == 0) {
      %key = %e.data;
      %state = 1;
    } else {
      %p.postMessage(_decrypt(%key, %e.data));
    }
  };
}

/* 
共用~worker, 専用~workerどちらとして利用されていても,~supportする
◎
support being used as a shared worker as well as a dedicated worker
 */
if ('onmessage' in this) /* 専用~worker */
  onmessage = handleMessage;
else /* 共用~worker */
  onconnect = function (%e) { %e.port.onmessage = handleMessage; }

/* 
“暗号” 関数:
◎
the "crypto" functions:
 */

function _generateKeyPair() {
  return [Math.random(), Math.random()];
}

function _encrypt(%k, %s) {
  return 'encrypted-' + %k + ' ' + %s;
}

function _decrypt(%k, %s) {
  return %s.substr(%s.indexOf(' ')+1);
}

ここでの暗号~関数は、 単なる~stubであり,本当の暗号化は行わないことに注意。 ◎ Note that the crypto functions here are just stubs and don't do real cryptography.

この~libraryは、 次のようにも利用できる: ◎ This library could be used as follows:

<!DOCTYPE HTML>
<html>
 <head>
  <meta charset="utf-8">
  <title>Worker example: Crypto library</title>
  <script>
   const cryptoLib = new Worker('libcrypto-v1.js'); /* 
あるいは 'libcrypto-v2.js' も利用できる
◎
or could use 'libcrypto-v2.js'
 */
   function startConversation(%source, %message) {
     const %messageChannel = new MessageChannel();
     %source.postMessage(%message, [%messageChannel.port2]);
     return %messageChannel.port1;
   }
   function getKeys() {
     let %state = 0;
     startConversation(cryptoLib, "genkeys").onmessage = function (%e) {
       if (%state === 0)
         document.getElementById('public').value = %e.data;
       else if (%state === 1)
         document.getElementById('private').value = %e.data;
       %state += 1;
     };
   }
   function enc() {
     const %port = startConversation(%cryptoLib, "encrypt");
     %port.postMessage(document.getElementById('public').value);
     %port.postMessage(document.getElementById('input').value);
     %port.onmessage = function (%e) {
       document.getElementById('input').value = %e.data;
       %port.close();
     };
   }
   function dec() {
     const %port = startConversation(%cryptoLib, "decrypt");
     %port.postMessage(document.getElementById('private').value);
     %port.postMessage(document.getElementById('input').value);
     %port.onmessage = function (%e) {
       document.getElementById('input').value = %e.data;
       %port.close();
     };
   }
  </script>
  <style>
   textarea { display: block; }
  </style>
 </head>
 <body onload="getKeys()">
  <fieldset>
   <legend>Keys</legend>
   <p><label>Public Key: <textarea id="public"></textarea></label></p>
   <p><label>Private Key: <textarea id="private"></textarea></label></p>
  </fieldset>
  <p><label>Input: <textarea id="input"></textarea></label></p>
  <p><button onclick="enc()">Encrypt</button> <button onclick="dec()">Decrypt</button></p>
 </body>
</html>

この~APIの後の~versionでは、 すべての暗号~作業を下位workerに負荷委譲するよう求まれるかもしれない。 これは、 次のように行うこともできる: ◎ A later version of the API, though, might want to offload all the crypto work onto subworkers. This could be done as follows:

function handleMessage(%e) {
  if (%e.data == "genkeys")
    genkeys(%e.ports[0]);
  else if (%e.data == "encrypt")
    encrypt(%e.ports[0]);
  else if (%e.data == "decrypt")
    decrypt(%e.ports[0]);
}

function genkeys(%p) {
  var generator = new Worker('libcrypto-v2-generator.js');
  generator.postMessage('', [%p]);
}

function encrypt(%p) {
  %p.onmessage = function (%e) {
    var %key = %e.data;
    var encryptor = new Worker('libcrypto-v2-encryptor.js');
    encryptor.postMessage(%key, [%p]);
  };
}

function encrypt(%p) {
  %p.onmessage = function (%e) {
    var %key = %e.data;
    var decryptor = new Worker('libcrypto-v2-decryptor.js');
    decryptor.postMessage(%key, [%p]);
  };
}

/* 
共用~worker, 専用~workerどちらとして利用されていても,~supportする
◎
support being used as a shared worker as well as a dedicated worker
 */
if ('onmessage' in this) /* 
専用~worker
◎
dedicated worker
 */
  onmessage = handleMessage;
else /* 
共用~worker
◎
shared worker
 */
  onconnect = function (%e) { %e.ports[0].onmessage = handleMessage };

小分けにされた下位workerは: ◎ The little subworkers would then be as follows.

鍵~pairの生成-用: ◎ For generating key pairs:

onmessage = function (%e) {
  var %k = _generateKeyPair();
  %e.ports[0].postMessage(%k[0]);
  %e.ports[0].postMessage(%k[1]);
  close();
}

function _generateKeyPair() {
  return [Math.random(), Math.random()];
}

暗号化-用: ◎ For encrypting:

onmessage = function (%e) {
  var %key = %e.data;
  %e.ports[0].onmessage = function (%e) {
    var %s = %e.data;
    postMessage(_encrypt(%key, %s));
  }
}

function _encrypt(%k, %s) {
  return 'encrypted-' + %k + ' ' + %s;
}

復号化-用: ◎ For decrypting:

onmessage = function (%e) {
  var %key = %e.data;
  %e.ports[0].onmessage = function (%e) {
    var %s = %e.data;
    postMessage(_decrypt(%key, %s));
  }
}

function _decrypt(%k, %s) {
  return %s.substr(%s.indexOf(' ')+1);
}

~APIは変更されてないので、 ~APIの利用者は,これが起きていることを知る必要すらない。 ~libraryは、 ~message~channelを利用して~dataを受容しているが, 自身の~APIを変更することなく下位workerに委任できる。 ◎ Notice how the users of the API don't have to even know that this is happening — the API hasn't changed; the library can delegate to subworkers without changing its API, even though it is accepting data using message channels.

`この例を~onlineで見る@~DEMO/crypto/page.html$ 。 ◎ View this example online.

10.1.3. ~tutorial

10.1.3.1. 専用~workerの作成-法
◎非規範的

~workerを作成するためには~JS~fileの~URLを要する。 その~fileの~URLのみを引数として `new Worker()$m 構築子を呼出せば、 ~workerが作成されて返される: ◎ Creating a worker requires a URL to a JavaScript file. The Worker() constructor is invoked with the URL to that file as its only argument; a worker is then created and returned:

var %worker = new Worker('helper.js');

`古典~script$でなく`~module~script$として解釈させたいときは、 記し方を少し違える必要がある: ◎ If you want your worker script to be interpreted as a module script instead of the default classic script, you need to use a slightly different signature:

var %worker = new Worker('helper.mjs', { type: "module" });
10.1.3.2. 専用~workerとの通信-法
◎非規範的

専用~workerは暗黙的に `MessagePort$I ~objを利用する。 したがって、[ 有構造~dataの送信-法, ~binary~dataの転送-法, 他の~portへの転送-法 ]など, `MessagePort$I と同じ特能を~supportする。 ◎ Dedicated workers use MessagePort objects behind the scenes, and thus support all the same features, such as sending structured data, transferring binary data, and transferring other ports.

専用~workerから~messageを受信するためには、 `Worker$I ~objの `onmessage$m `~event~handler~IDL属性$を利用する: ◎ To receive messages from a dedicated worker, use the onmessage event handler IDL attribute on the Worker object:

%worker.onmessage = function (%event) { ... };

`addEventListener()$m ~methodも利用できる。 ◎ You can also use the addEventListener() method.

注記: 専用~workerに利用される暗黙的な `MessagePort$I には、 その作成-時に`~port~message~queue$が暗黙的に備わり,可能化される。 したがって、 `Worker$I ~interfaceには, `MessagePort$I ~interfaceの `start()$m ~methodに等価なものはない。 ◎ The implicit MessagePort used by dedicated workers has its port message queue implicitly enabled when it is created, so there is no equivalent to the MessagePort interface's start() method on the Worker interface.

~dataを~workerへ送信するためには、 `postMessage()$mW ~methodを利用する。 有構造~dataもこの通信~channelを通して送信できる。 (何個かの) `ArrayBuffer$I ~objを効率的に送信する(~cloneせずに転送する)ためには、 それらを配列にして 2 個目の引数に渡す。 ◎ To send data to a worker, use the postMessage() method. Structured data can be sent over this communication channel. To send ArrayBuffer objects efficiently (by transferring them rather than cloning them), list them in an array in the second argument.

%worker.postMessage({
  operation: 'find-edges',
  input: %buffer, /* 
`ArrayBuffer^I ~obj
◎
an ArrayBuffer object
 */
  threshold: 0.6,
}, [%buffer]);

~workerの内側で~messageを受信するときは、 `onmessage$m `~event~handler~IDL属性$を利用する。 ◎ To receive a message inside the worker, the onmessage event handler IDL attribute is used.

onmessage = function (%event) { ... };

ここでもまた `addEventListener()$m ~methodを利用できる。 ◎ You can again also use the addEventListener() method.

いずれの場合も,~dataは~event~objの `data$m 属性に供される。 ◎ In either case, the data is provided in the event object's data attribute.

~messageの返信-時にも, `postMessage()$m を利用する。 有構造~dataも同じように~supportされる。 ◎ To send messages back, you again use postMessage(). It supports the structured data in the same manner.

postMessage(%event.data.input, [%event.data.input]); /* 
~bufferを返送
◎
transfer the buffer back
 */
10.1.3.3. 共用~worker
◎非規範的

共用~workerは、 その作成-時に利用した~scriptの~URLにより識別され, 名前(省略可能)も明示的に付与できる。 名前があれば、 特定0の共用~workerに対し複数の~instanceを開始することも可能になる。 ◎ Shared workers are identified by the URL of the script used to create it, optionally with an explicit name. The name allows multiple instances of a particular shared worker to be started.

共用~workerは,生成元の~scopeに属する(生成元ごとに分別される)。 互いに異なる~siteが同じ名前のものを利用したとしても,衝突することはない。 しかしながら、 同じ~site内の 2 つの~pageで, 同じ共用~worker名に異なる~script~URLを伴わせて利用した場合、 失敗することになる。 ◎ Shared workers are scoped by origin. Two different sites using the same names will not collide. However, if a page tries to use the same shared worker name as another page on the same site, but with a different script URL, it will fail.

共用~workerの作成には、 `new SharedWorker()$m 構築子を利用する。 この構築子は、 最初の 2 個の引数に[ 利用する~scriptの~URL, ~workerの名前(省略可能) ]をとる。 ◎ Creating shared workers is done using the SharedWorker() constructor. This constructor takes the URL to the script to use for its first argument, and the name of the worker, if any, as the second argument.

var %worker = new SharedWorker('service.js');

共用~workerと通信するときは、 明示的な `MessagePort$I ~objを通して行う。 `new SharedWorker()$m 構築子から返される~objは、 その~portへの参照を `port$mW 属性に保持する。 ◎ Communicating with shared workers is done with explicit MessagePort objects. The object returned by the SharedWorker() constructor holds a reference to the port on its port attribute.

%worker.port.onmessage = function (%event) { ... };
%worker.port.postMessage('some message');
%worker.port.postMessage({
   foo: 'structured',
   bar: ['data', 'also', 'possible']
});

共用~workerの内側では、 `connect$et ~eventを利用して, 新たな~clientからの接続が告知される。 新たな~client用の~portは、 この~event~objの `source$m 属性により与えられる。 ◎ Inside the shared worker, new clients of the worker are announced using the connect event. The port for the new client is given by the event object's source attribute.

onconnect = function (%event) {
  var %newPort = %event.source;
  /* 
~listenerを設定しておく
◎
set up a listener
 */
  %newPort.onmessage = function (%event) { ... };
  /* 
~portに~messageを返信する
◎
send a message back to the port
 */
  %newPort.postMessage('ready!'); /* 
もちろん、
有構造~dataも返信できる
◎
can also send structured data, of course
 */
};

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

◎表記記号

10.2. 基盤

この仕様は、 2 種類の~worker — 専用~worker, 共用~worker — を定義する。 専用~workerは,作成-時にその作成元へ~linkされるが、 ~message~portを利用することで, 他の閲覧~文脈や~workerへも通信できる。 一方で、 共用~workerには,名前があり、 その作成-後に それへの参照を得しておけば, 同じ`生成元$上で走っているどの~scriptとも通信できる。 `Service Workers^cite は、 また別の種類の~workerを定義する。 `SW$r ◎ This standard defines two kinds of workers: dedicated workers, and shared workers. Dedicated workers, once created, are linked to their creator, but message ports can be used to communicate from a dedicated worker to multiple other browsing contexts or workers. Shared workers, on the other hand, are named, and once created any script running in the same origin can obtain a reference to that worker and communicate with it. Service Workers defines a third kind. [SW]

10.2.1. 大域~scope

大域~scopeが~workerの “内側” である。 ◎ The global scope is the "inside" of a worker.

【 すなわち、 同じ~workerが, “二つの顔” — その内側で走っている~scriptに公開する `WorkerGlobalScope$I ~obj(大域~scope), それを外側から利用する~scriptに公開する `Worker$I ~obj — を持つ (共用~workerの場合、 後者は,当の~workerを共有している大域~環境の個数だけ複数あり得る)。 】

10.2.1.1. `WorkerGlobalScope^I 共通~interface
[Exposed=Worker]
interface `WorkerGlobalScope@I : `EventTarget$I {
  readonly attribute `WorkerGlobalScope$I `self$m;
  readonly attribute `WorkerLocation$I `location$m;
  readonly attribute `WorkerNavigator$I `navigator$m;
  undefined `importScripts$m((`TrustedScriptURL$I or USVString)... %urls);

  attribute `OnErrorEventHandler$I `onerror$m;
  attribute `EventHandler$I `onlanguagechange$m;
  attribute `EventHandler$I `onoffline$m;
  attribute `EventHandler$I `ononline$m;
  attribute `EventHandler$I `onrejectionhandled$m;
  attribute `EventHandler$I `onunhandledrejection$m;
};

`WorkerGlobalScope$I は、 各種~worker大域~scope~objの基底~classとして~serveする — そのような~objの型には、 特定的に次に挙げるものが含まれる ⇒# `DedicatedWorkerGlobalScope$I, `SharedWorkerGlobalScope$I, `ServiceWorkerGlobalScope$I ◎ WorkerGlobalScope serves as the base class for specific types of worker global scope objects, including DedicatedWorkerGlobalScope, SharedWorkerGlobalScope, and ServiceWorkerGlobalScope.

各 `WorkerGlobalScope$I ~objには、 次に挙げるものが結付けられる: ◎ ↓

`所有者~集合@wG ◎ A WorkerGlobalScope object has an associated owner set\
[ `Document$I / `WorkerGlobalScope$I ]~objたちが成す`集合$ — 初期~時は空とする。 この~workerを[ 作成する/得する ]ときに拡充される。 ◎ (a set of Document and WorkerGlobalScope objects). It is initially empty and populated when the worker is created or obtained.
注記: 単独の所有者ではなく`集合$にされているのは、 `SharedWorkerGlobalScope$I ~objに適応するためである。 ◎ It is a set, instead of a single owner, to accommodate SharedWorkerGlobalScope objects.
`種別@wG ◎ A WorkerGlobalScope object has an associated type\
作成-時に,次のいずれかに設定される ⇒# `classic^l / `module^l ◎ ("classic" or "module"). It is set during creation.
`~URL@wG ◎ A WorkerGlobalScope object has an associated url\
~NULL または`~URL$ — 初期~時は ~NULL とする。 ◎ (null or a URL). It is initially null.
【 少なくとも,~APIから~accessされる時点までには、 ~NULL 以外に設定されることになる。 】
`名前@wG ◎ A WorkerGlobalScope object has an associated name\
文字列 — 作成-時に設定される。 ◎ (a string). It is set during creation.

注記: `名前$wGの意味論は、 `WorkerGlobalScope$I の下位classごとに異なり得る: ◎ The name can have different semantics for each subclass of WorkerGlobalScope.\

  • `DedicatedWorkerGlobalScope$I 用には、 単純に開発者が給する名前であり,ほぼ~debug目的に限り有用になる。 ◎ For DedicatedWorkerGlobalScope instances, it is simply a developer-supplied name, useful mostly for debugging purposes.\
  • `SharedWorkerGlobalScope$I 用には、 共通な共用~workerへの参照を `new SharedWorker()$m 構築子を介して得することを許容する。 ◎ For SharedWorkerGlobalScope instances, it allows obtaining a reference to a common shared worker via the SharedWorker() constructor.\
  • `ServiceWorkerGlobalScope$I 用には、 イミを成さない (そのため、 ~JS~APIを通して公開されることもない)。 ◎ For ServiceWorkerGlobalScope objects, it doesn't make sense (and as such isn't exposed through the JavaScript API at all).
`施策~容器@wG ◎ A WorkerGlobalScope object has an associated policy container\
`施策~容器$ — 初期~時は新たな`施策~容器$とする。 ◎ (a policy container). It is initially a new policy container.
`埋込元~施策@wG ◎ A WorkerGlobalScope object has an associated embedder policy\
`埋込元~施策$ ◎ (an embedder policy).
`~module~map@wG ◎ A WorkerGlobalScope object has an associated module map.\
`~module~map$ — 初期~時は空とする。 ◎ It is a module map, initially empty.
`非同一-生成元~能力は隔離されるか@wG ◎ A WorkerGlobalScope object has an associated cross-origin isolated capability\
真偽値 — 初期~時は ~F とする。 ◎ boolean. It is initially false.
%workerGlobal.`self$m
%workerGlobal 自身を返す。 ◎ Returns workerGlobal.
%workerGlobal.`location$m
%workerGlobal の `WorkerLocation$I ~objを返す。 ◎ Returns workerGlobal's WorkerLocation object.
%workerGlobal.`navigator$m
%workerGlobal の `WorkerNavigator$I ~objを返す。 ◎ Returns workerGlobal's WorkerNavigator object.
%workerGlobal.`importScripts(...urls【!urls...】)$m
%urls を成す各~URLを — 渡された順に一つずつ — ~fetchして, 実行して, 結果を返す (あるいは、 どこかで不具合があれば例外を投出する)。 ◎ Fetches each URL in urls, executes them one-by-one in the order they are passed, and then returns (or throws if something went amiss).
`self@m 取得子~手続きは ⇒ ~RET コレ ◎ The self attribute must return the WorkerGlobalScope object itself.

`location@m 取得子~手続きは

  1. ~Assert: コレの`~worker所在~obj$ ~NEQ ε
  2. ~RET コレの`~worker所在~obj$

注記: `WorkerLocation$I ~objが作成されるのは, `WorkerGlobalScope$I ~objより後になるが、 それは~scriptからは観測し得ないので,問題にはならない。

◎ The location attribute must return the WorkerLocation object whose associated WorkerGlobalScope object is the WorkerGlobalScope object. ◎ While the WorkerLocation object is created after the WorkerGlobalScope object, this is not problematic as it cannot be observed from script.

`WorkerGlobalScope$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 objects implementing the WorkerGlobalScope interface:

~event~handler ~event~handler~event型
`onerror@m `error$et
`onlanguagechange@m `languagechange$et
`onoffline@m `offline$et
`ononline@m `online$et
`onrejectionhandled@m `rejectionhandled$et
`onunhandledrejection@m `unhandledrejection$et
10.2.1.2. 専用~workerと `DedicatedWorkerGlobalScope^I ~interface
[Global=(Worker,DedicatedWorker),Exposed=DedicatedWorker]
interface `DedicatedWorkerGlobalScope@I : `WorkerGlobalScope$I {
  [Replaceable] readonly attribute DOMString `name$m;

  undefined `postMessage$m(any %message, sequence<`object$> %transfer);
  undefined `~postMessageO$m(any %message, optional `StructuredSerializeOptions$I %options = {});
  undefined `close$m();

  `DedicatedWorkerGlobalScope$I includes `MessageEventTarget$I;
};

各 `DedicatedWorkerGlobalScope$I ~objには、 `内側~port@ が結付けられる — それは: ◎ DedicatedWorkerGlobalScope objects have an associated inside port\

  • `MessagePort$I ~objである。 ◎ (a MessagePort).\
  • 当の~worker作成-時に設定しておかれる~channelの一部を成すが,公開されない。 ◎ This port is part of a channel that is set up when the worker is created, but it is not exposed.\
  • 当の `DedicatedWorkerGlobalScope$I ~objより先に~garbage収集されてはならない。 ◎ This object must never be garbage collected before the DedicatedWorkerGlobalScope object.
%dedicatedWorkerGlobal.`name$m
%dedicatedWorkerGlobal の`名前$wG — すなわち, `new Worker()$m 構築子に与えた値 — を返す。 主に、 ~debug時に有用になる。 ◎ Returns dedicatedWorkerGlobal's name, i.e. the value given to the Worker constructor. Primarily useful for debugging.
%dedicatedWorkerGlobal.`postMessage(message, transfer【![, transfer]】)$m
%dedicatedWorkerGlobal.`~postMessageO(message [, options ])$m
~messageを~cloneして,それを %dedicatedWorkerGlobal に結付けられた `Worker$I ~objへ伝送する。 [ %transfer / [ %options の `transfer$m ~member ]]に、 ~cloneせずに転送する~objの~listを渡せる。 ◎ Clones message and transmits it to the Worker object associated with dedicatedWorkerGlobal. transfer can be passed as a list of objects that are to be transferred rather than cloned.
%dedicatedWorkerGlobal.`close()$m
%dedicatedWorkerGlobal を中止する。 ◎ Aborts dedicatedWorkerGlobal.

`name@m 取得子~手続きは ⇒ ~RET コレの`名前$wG ◎ The name getter steps are to return this's name.\

返される値は、 `new Worker$m 構築子を利用して~workerに与えた名前を表現する — これは首に、 ~debug目的に利用される。 ◎ Its value represents the name given to the worker using the Worker constructor, used primarily for debugging purposes.

`postMessage(message, transfer)@m ~method手続きは ⇒ ~RET コレの`内側~port$【!the port】上の `postMessage$mMP ~method手続き( %message, %transfer )

`~postMessageO(message, options)@m ~method手続きは ⇒ ~RET コレの`内側~port$【!the port】上の `~postMessageO$mMP ~method手続き( %message, %options )

◎ The postMessage(message, transfer) and postMessage(message, options) methods on DedicatedWorkerGlobalScope objects act as if, when invoked, it immediately invoked the respective postMessage(message, transfer) and postMessage(message, options) on the port, with the same arguments, and returned the same return value.

`~workerを~closeする@ ~algoは、 所与の ( %~worker大域~scope ) に対し: ◎ To close a worker, given a workerGlobal, run these steps:

  1. %~worker大域~scope に`関連な~agent$の`~event~loop$aGの`~task~queue$に追加された`~task$は、 すべて破棄する ◎ Discard any tasks that have been added to workerGlobal's relevant agent's event loop's task queues.
  2. %~worker大域~scope の`~close中か$wG ~SET ~T (これにより、 ~taskがそれ以上~queueされることはなくなる。) ◎ Set workerGlobal's closing flag to true. (This prevents any further tasks from being queued.)
`close()@m ~method手続きは ⇒ `~workerを~closeする$( コレ ) ◎ The close() method steps are to close a worker given this.
10.2.1.3. 共用~workerと `SharedWorkerGlobalScope^I ~interface
[Global=(Worker,SharedWorker),Exposed=SharedWorker]
interface `SharedWorkerGlobalScope@I : `WorkerGlobalScope$I {
  [Replaceable] readonly attribute DOMString `~nameS$m;

  undefined `~closeS$m();

  attribute `EventHandler$I `onconnect$m;
};

各 `SharedWorkerGlobalScope$I ~objには、 次に挙げるものが結付けられる: ◎ A SharedWorkerGlobalScope object has associated\

  • `構築子~生成元@wG ⇒ ある`生成元$ ◎ constructor origin (an origin),\
  • `構築子~URL@wG ⇒ ある`~URL~record$ ◎ constructor URL (a URL record),\
  • `資格証@wG ⇒ ある`資格証~mode$rq ◎ and credentials (a credentials mode).\

これらは、 `~workerを走らす$ ~algo内で当の~objが作成されるとき,初期化される。 ◎ They are initialized when the SharedWorkerGlobalScope object is created, in the run a worker algorithm.

共用~workerは、 その `SharedWorkerGlobalScope$I ~obj上の `connect$et ~eventを通して,各~接続の~message~portを受信する。 ◎ Shared workers receive message ports through connect events on their SharedWorkerGlobalScope object for each connection.

%sharedWorkerGlobal.`~nameS$m
%sharedWorkerGlobal の`名前$wG — すなわち, `new SharedWorker()$m 構築子に与えた値 — を返す。 同じ名前を再利用すれば、 同じ共用~worker(および `SharedWorkerGlobalScope$I )に複数の `SharedWorker$I ~objを対応させれる。 ◎ Returns sharedWorkerGlobal's name, i.e. the value given to the SharedWorker constructor. Multiple SharedWorker objects can correspond to the same shared worker (and SharedWorkerGlobalScope), by reusing the same name.
%sharedWorkerGlobal.`~closeS()$m
%sharedWorkerGlobal を中止する。 ◎ Aborts sharedWorkerGlobal.

`~nameS@m 取得子~手続きは ⇒ ~RET コレの`名前$wG ◎ The name getter steps are to return this's name.\

返される値は、 `new SharedWorker()$m 構築子を利用して~workerへの参照を得するときに利用できる名前を表現する。 ◎ Its value represents the name that can be used to obtain a reference to the worker using the SharedWorker constructor.

`~closeS()@m ~method手続きは ⇒ `~workerを~closeする$( コレ ) ◎ The close() method steps are to close a worker given this.

`SharedWorkerGlobalScope$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 objects implementing the SharedWorkerGlobalScope interface:

~event~handler ~event~handler~event型
`onconnect@m `connect$et

10.2.2. ~event~loop

`~worker~event~loop$の`~task~queue$内にあり得る`~task$は、[ ~event, ~callback, ~networking活動 ]に限られる。 これらの`~worker~event~loop$は、 `~workerを走らす$~algoにより作成される。 ◎ A worker event loop's task queues only have events, callbacks, and networking activity as tasks. These worker event loops are created by the run a worker algorithm.

各 `WorkerGlobalScope$I ~objは、 `~close中か@wG を有する — それは、 真偽値であり: ◎ Each WorkerGlobalScope object has a closing flag,\

  • 初期~時は ~F になるモノトスル。 下の処理~model節の~algoにより, ~T にされ得る。 ◎ which must be initially false, but which can get set to true by the algorithms in the processing model section below.
  • ~T になったときは、 それ以降に[ `~event~loop$の`~task~queue$に追加される`~task$ ]を破棄するモノトスル (~queue内にすでにある~taskは、 他が指定されない限り,影響されない)。 実質的には、 ~T になったら,~timerは発火を止め, 処理待ちにあるすべての~background演算の通知は取り除かれる, 等々が行われることになる。 ◎ Once the WorkerGlobalScope's closing flag is set to true, the event loop's task queues must discard any further tasks that would be added to them (tasks already on the queue are unaffected except where otherwise specified). Effectively, once the closing flag is true, timers stop firing, notifications for all pending background operations are dropped, etc.

10.2.3. ~workerの存続期間

~workerは、 `~message~channel$とそれらの `MessagePort$I ~objを通して,他の~workerや`~window$と通信する。 ◎ Workers communicate with other workers and with Windows through message channels and their MessagePort objects.

各 `WorkerGlobalScope$I ~obj %G は、 `~port~list@wG を有する — それは: ◎ Each WorkerGlobalScope object worker global scope has a list of the worker's ports,\

  • 次を満たす `MessagePort$I ~obj %P すべてからなる ⇒ [ %P は別の `MessagePort$I ~obj %Q と`連絡-$されている ]~AND[ %G は %P, %Q のうち %P のみを所有している† ] ◎ which consists of all the MessagePort objects that are entangled with another port and that have one (but only one) port owned by worker global scope.\

    【† おそらく,[ %P に`関連な大域~obj$ ~EQ %G ~NEQ %Q に`関連な大域~obj$ ]を意味する。 】

  • `専用~worker$の事例では 【すなわち, %G は `DedicatedWorkerGlobalScope$I ~objである】、 暗黙的な~port【 %G の`内側~port$】も含む。 【前~項の条件を満たす限り。】 ◎ This list includes the implicit MessagePort in the case of dedicated workers.

所与の`環境~設定群~obj$ %O の下で~workerを[ 作成する/得する ]ときに `関連な所有者として追加するもの@ は、 %O により指定される`大域~obj$enV %G に応じて,次のいずれかになる: ◎ Given an environment settings object o when creating or obtaining a worker, the relevant owner to add depends on the type of global object specified by o.\

  • `WorkerGlobalScope$I である(すなわち,入子な専用~workerを作成している)場合 ⇒ %G ◎ If o's global object is a WorkerGlobalScope object (i.e., if we are creating a nested dedicated worker), then the relevant owner is that global object.\
  • `Window$I である場合 ⇒ %G に`結付けられた文書$ ◎ Otherwise, o's global object is a Window object, and the relevant owner is that Window's associated Document.

各~UAは、 `次回の読込nまでの共用~worker制限時間@ を有する — それは、 `実装定義$な何らかの短い時間である。 これは、[ ある~pageを読込んでいる間に当の~pageが共用~workerに再び繋がろうとしている事例 ]で[ 当の~UAが,共用~workerは いつまで長く生残ることを許容するか ]を表現する。 ~UAは、 これを 0 より大きい値に設定することで,[ 利用者が ある~siteの中で~pageから~pageへ~navigateするとき ]に[ 当の~siteが利用している共用~workerを開始し直す~cost ]を避けれるようになる。 ◎ A user agent has an implementation-defined value, the between-loads shared worker timeout, which is some small amount of time. This represents how long the user agent allows shared workers to survive while a page is loading, in case that page is going to contact the shared worker again. Setting this value to greater than zero lets user agents avoid the cost of restarting a shared worker used by a site when the user is navigating from page to page within that site.

注記: `次回の読込nまでの共用~worker制限時間$用の代表的な値は、 5 秒くらいになろう。 ◎ A typical value for the between-loads shared worker timeout might be 5 seconds.


所与の `WorkerGlobalScope$I %G が所与の時点で: ◎ ↓

  • `作動中なため必要@ ( `actively needed^en )であるとは、[ %G の`所有者~集合$wG内に ~OR↓ を満たすものが在る ]ことをいう:

    • [ `Document$I である ]~AND[ `全部的に作動中$である ]
    • [ `WorkerGlobalScope$I である ]~AND[ `作動中なため必要$である ]
    ◎ A WorkerGlobalScope global is actively needed if the following algorithm returns true: • For each owner of global's owner set: •• If owner is a Document, and owner is fully active, then return true. •• If owner is a WorkerGlobalScope that is actively needed, then return true. • Return false.
  • `保護され@ ている( `protected^en )とは、 ~AND↓ が満たされることをいう:

    • %G は`作動中なため必要$である
    • ~OR↓:

      • %G は `SharedWorkerGlobalScope$I である
      • %G の`~port~list$wGは`空$でない
      • %G は待機中な~timerを有する
      • %G は~database~transaction【 `INDEXEDDB$r 】を有する
      • %G は~network接続を有する
    ◎ A WorkerGlobalScope global is protected if the following algorithm returns true: • If global is not actively needed, then return false. • If global is a SharedWorkerGlobalScope, then return true. • If global's the worker's ports is not empty, then return true. • If global has outstanding timers, database transactions, or network connections, then return true. • Return false.
  • `許可-可能@ ( `permissible^en )であるとは、 ~OR↓ が満たされることをいう:

    • %G の`所有者~集合$wGは`空$でない
    • ~AND↓:

      • %G は `SharedWorkerGlobalScope$I である
      • %G の`所有者~集合$wGが最後に`空$であったときから~UAの`次回の読込nまでの共用~worker制限時間$を過ぎていない
      • ~UAは、 次を満たす`~navigable$を有する ⇒ それにて`作動中な文書$navは`完全に読込まれ$ていない
    ◎ A WorkerGlobalScope global is permissible if the following algorithm returns true: • If global's owner set is not empty, then return true. • If all of the following are true: •• global is a SharedWorkerGlobalScope; •• global's owner set has been empty for no more than the user agent's between-loads shared worker timeout; and •• the user agent has a navigable whose active document is not completely loaded, • then return true. • Return false.
  • `休止-可能@ ( `suspendable^en )であるとは、 次が満たされることをいう ⇒ [ %G は`作動中なため必要$でない ]~AND[ %G は`許可-可能$である ] ◎ A WorkerGlobalScope global is suspendable if the following algorithm returns true: • If global is actively needed, then return false. • If global is permissible, then return true. • Return false.

注記: これらの概念は、 この仕様の他所における規範的な要件に利用される: ◎ These concepts are used elsewhere in the specification's normative requirements as follows:

  • ~workerは、 `保護され$なくなったときから`許可-可能$でなくなるときまでは, `孤立~workerとして~closeされ@#step-closing-orphan-workers$るようになる。 ◎ Workers get closed as orphans between when they stop being protected and when they stop being permissible.
  • ~workerは、 `休止-可能$かどうかに基づいて[ `休止される/休止されない@#step-suspending-workers$ ]ようになる。 ◎ Workers get suspended or un-suspended based on whether they are suspendable.
  • ~workerのうち~closeされたが実行し続けているものは、 `作動中なため必要$でなくなったなら, ~UAの裁量で`終了され得る@#terminate-rampant-workers$。 ◎ Workers that have been closed, but keep executing, can be terminated at the user agent's discretion, once they stop being actively needed.

どの `WorkerGlobalScope$I も[ `作動中なため必要$であるならば`保護され$ている【明らかに逆であろう】/ `保護され$ているならば`許可-可能$である ](が,これらの逆は成立しない)ことに注意。 ◎ Note that every WorkerGlobalScope that is actively needed is protected, and every WorkerGlobalScope that is protected is permissible. (But the converses do not hold.)

`WorkerGlobalScope$I %G が[ `保護され$ていること, `許可-可能$であること ]の重要な相違は、 前者は[ %G の所有者たちが成す推移的な集合が 1 個以上の`全部的に作動中$な`文書$を包含する場合 ]に限り満たされる一方で, 後者は[ %G の所有者たちが成す推移的な集合を成す すべての`文書$が`~BF~cache$内に在る場合 ]でも満たされ得ることである。 ◎ An important difference between protected and permissible is that a WorkerGlobalScope is protected only if its transitive set of owners contains at least one fully active Document, whereas a WorkerGlobalScope can be permissible even if all the Documents in its transitive set of owners are in bfcache.

注記: `次回の読込nまでの共用~worker制限時間$は,[ `許可-可能$, `保護され$ている ]のうち前者の定義にしか波及しないので、 実装には,[ この制限時間に達するまで共用~workerたちの生存を保つこと ]は要求されないが、 達したなら,共用~workerたちを~closeすることが要求される。 ◎ The between-loads shared worker timeout only influences the definition of permissible, not protected, and so implementations are not required to keep shared workers alive for that duration. Rather, they are required to close shared workers after the timeout is reached.

10.2.4. 処理~model

ある~script用の `~workerを走らす@ ~algoは、 所与の ⇒# %~worker ( `Worker$I / `SharedWorker$I ~obj ), %~URL ( `~URL$ ), %外側~設定群 ( `環境~設定群~obj$ ), %外側~port ( `MessagePort$I ~obj ), %options ( `WorkerOptions$I 辞書 ) ◎終 に対し: ◎ When a user agent is to run a worker for a script with Worker or SharedWorker object worker, URL url, environment settings object outside settings, MessagePort outside port, and a WorkerOptions dictionary options, it must run the following steps.

  1. %共用か ~LET ~IS[ %~worker は `SharedWorker$I ~objである ] ◎ Let is shared be true if worker is a SharedWorker object, and false otherwise.
  2. %所有者 ~LET %外側~設定群 から与えられる,`関連な所有者として追加するもの$ ◎ Let owner be the relevant owner to add given outside settings.
  3. %安全でない~worker作成~時刻 ~LET `安全でない共有される現在の時刻$ ◎ Let unsafeWorkerCreationTime be the unsafe shared current time.
  4. %~agent ~LET `専用/共用~worker~agentを得する$( %外側~設定群, %共用か ) ◎ Let agent be the result of obtaining a dedicated/shared worker agent given outside settings and is shared.\

    この手続きの以降は, %~agent 内で走らすとする ◎ Run the rest of these steps in that agent.

  5. %~realm実行~文脈 ~LET 次のように~custom化する下で, %~agent 内で`新たな~realmを作成する$ ⇒ 大域~obj用には, %共用か に応じて次を作成する ⇒# ~T ならば 新たな `SharedWorkerGlobalScope$I ~obj / ~F ならば 新たな `DedicatedWorkerGlobalScope$I ~obj ◎ Let realm execution context be the result of creating a new realm given agent and the following customizations: • For the global object, if is shared is true, create a new SharedWorkerGlobalScope object. Otherwise, create a new DedicatedWorkerGlobalScope object.
  6. %~worker大域~scope ~LET %~realm実行~文脈 の`大域~obj$rM成分 ◎ Let worker global scope be the global object of realm execution context's Realm component.

    注記: これは、 前~段で作成した[ `SharedWorkerGlobalScope^I / `DedicatedWorkerGlobalScope^I ]~objになる。 ◎ This is the DedicatedWorkerGlobalScope or SharedWorkerGlobalScope object created in the previous step.

  7. %内側~設定群 ~LET `~workerの環境~設定群~objを設定しておく$( %~realm実行~環境, %外側~設定群, %安全でない~worker作成~時刻 ) ◎ Set up a worker environment settings object with realm execution context, outside settings, and unsafeWorkerCreationTime, and let inside settings be the result.
  8. %~worker大域~scope の`名前$wG ~SET %options[ "`name$mb" ] ◎ Set worker global scope's name to options["name"].
  9. %~worker大域~scope の`所有者~集合$wGに %所有者 を`付加する$set ◎ Append owner to worker global scope's owner set.
  10. ~IF[ %共用か ~EQ ~T ] ⇒ %~worker大域~scope の ⇒# `構築子~生成元$wG ~SET %外側~設定群 の`生成元$enV, `構築子~URL$wG ~SET %~URL, `種別$wG ~SET %options[ "`type$mb" ], `資格証$wG ~SET %options[ `credentials$mb" ] ◎ If is shared is true, then: • Set worker global scope's constructor origin to outside settings's origin. • Set worker global scope's constructor URL to url. • Set worker global scope's type to options["type"]. • Set worker global scope's credentials to the value of options's credentials member.
  11. %行先 ~LET %共用か に応じて ⇒# ~T ならば `sharedworker^l / ~F ならば `worker^l ◎ Let destination be "sharedworker" if is shared is true, and "worker" otherwise.
  12. 次に従って~scriptを得する — %options[ "`type$mb" ] に応じて: ◎ Obtain script by switching on options["type"]:

    • `classic^l ⇒ `~worker用~古典~scriptを~fetchする$( ↓ ) ⇒# %~URL, %外側~設定群, %行先, %内側~設定群, %完了-時の手続き†, %~fetchを遂行する† ◎ "classic" • Fetch a classic worker script given url, outside settings, destination, inside settings, and with onComplete and performFetch as defined below.
    • `module^l ⇒ `~module~worker~script~graphを~fetchする$( ↓ ) ⇒# %~URL, %外側~設定群, %行先, %options[ `credentials^l ], %内側~設定群, %完了-時の手続き†, %~fetchを遂行する† ◎ "module" • Fetch a module worker script graph given url, outside settings, destination, the value of the credentials member of options, inside settings, and with onComplete and performFetch as defined below.

    † 上で利用される[ %完了-時の手続き, %~fetchを遂行する ]は、 以下に定義される: ◎ ↑

    %~fetchを遂行する は,`~fetch~hookを遂行する~algo$であり、 所与の ( %要請, `~top-levelか$V, `~custom~fetch応答の処理n$V ) に対し,次を遂行する: ◎ In both cases, let performFetch be the following perform the fetch hook given request, isTopLevel and processCustomFetchResponse:

    1. ~IF[ %~top-levelか ~EQ ~F ]:

      1. %要請 を`~fetchする$ — 次を与える下で ⇒ `応答の本体を消費する処理n$i ~SET %~custom~fetch応答の処理n
      2. ~RET
      ◎ If isTopLevel is false, fetch request with processResponseConsumeBody set to processCustomFetchResponse, and abort these steps.
    2. %要請 の`予約-済み~client$rq ~SET %内側~設定群 ◎ Set request's reserved client to inside settings.
    3. %要請 を`~fetchする$ — 次を与える下で: ◎ Fetch request with\

      • `応答の本体を消費する処理n$i ~SET 所与の ( `応答$ %応答, [ ~NULL / `失敗^i / `~byte列$ ] %本体~byte列 ) に対し,次を走らす手続き: ◎ processResponseConsumeBody set to the following steps given response response and null, failure, or a byte sequence bodyBytes:

        1. %~worker大域~scope の`~URL$wG ~SET %応答 の`~URL$rs ◎ Set worker global scope's url to response's url.
        2. `~worker大域~scopeの施策~容器を初期化する$( %~worker大域~scope, %応答, %内側~設定群 ) ◎ Initialize worker global scope's policy container given worker global scope, response, and inside settings.
        3. ~IF[ `大域~obj用に~CSP初期化を走らす$( %~worker大域~scope ) ~EQ `阻止される^i `CSP$r ] ⇒ %応答 ~SET `~network~error$ ◎ If the Run CSP initialization for a global object algorithm returns "Blocked" when executed upon worker global scope, set response to a network error. [CSP]
        4. ~IF[ %~worker大域~scope の`埋込元~施策$wGの`値$embPは`非同一-生成元~隔離と互換$である ]~AND[ %共用か ~EQ ~T ] ⇒ %~agent の`~agent~cluster$の`非同一-生成元~隔離~mode$agC ~SET [ `logical$coI / `concrete$coI ] — どちらが選ばれるかは、 `実装定義$とする ◎ If worker global scope's embedder policy's value is compatible with cross-origin isolation and is shared is true, then set agent's agent cluster's cross-origin isolation mode to "logical" or "concrete". The one chosen is implementation-defined.

          これは,本当は当の~agent~clusterが作成されるとき設定されるべきだが、 この節を設計し直すことが要求される。 ◎ This really ought to be set when the agent cluster is created, which requires a redesign of this section.

        5. ~IF[ `大域~objの埋込元~施策を検査する$( %~worker大域~scope, %外側~設定群, %応答 ) ~EQ ~F ] ⇒ %応答 ~SET `~network~error$ ◎ If the result of checking a global object's embedder policy with worker global scope, outside settings, and response is false, then set response to a network error.
        6. ~IF[ %~agent の`~agent~cluster$の`非同一-生成元~隔離~mode$agC ~EQ `concrete$coI ] ⇒ %~worker大域~scope の`非同一-生成元~能力は隔離されるか$wG ~SET ~T ◎ Set worker global scope's cross-origin isolated capability to true if agent's agent cluster's cross-origin isolation mode is "concrete".
        7. ~IF[ %共用か ~EQ ~F ]~AND[ %所有者 の`非同一-生成元~能力は隔離されるか?$enV ~EQ ~F ] ⇒ %~worker大域~scope の`非同一-生成元~能力は隔離されるか$wG ~SET ~F ◎ If is shared is false and owner's cross-origin isolated capability is false, then set worker global scope's cross-origin isolated capability to false.
        8. ~IF[ %共用か ~EQ ~F ]~AND[ %応答 の`~URL$rsの`~scheme$url ~EQ `data^l ] ⇒ %~worker大域~scope の`非同一-生成元~能力は隔離されるか$wG ~SET ~F ◎ If is shared is false and response's url's scheme is "data", then set worker global scope's cross-origin isolated capability to false.

          注記: これは、 今の所は,保守的な既定である。 ~workerが一般に — および[ `data$sc ~URL【から構築された】~worker(その所有者とは非同一-生成元になる) ]が特に — 許可~施策の文脈において,どう扱われることになるか~~解明されるまでの間の。 詳細は、 `w3c/webappsec-permissions-policy 課題 #207@https://github.com/w3c/webappsec-permissions-policy/issues/207$ を見よ。 ◎ This is a conservative default for now, while we figure out how workers in general, and data: URL workers in particular (which are cross-origin from their owner), will be treated in the context of permissions policies. See w3c/webappsec-permissions-policy issue #207 for more details.

        9. %~custom~fetch応答の処理n( %応答, %本体~byte列 ) ◎ Run processCustomFetchResponse with response and bodyBytes.

    %完了-時の手続き は、 所与の ( %~script ) に対し: ◎ In both cases, let onComplete given script be the following steps:

    1. ~IF[ %~script ~EQ ~NULL ]~OR[ %~script の`再投出-用~error$sC ~NEQ ~NULL ]: ◎ If script is null or if script's error to rethrow is non-null, then:

      1. `大域~taskを~queueする$( `~DOM操作~task~source$, %~worker に`関連な大域~obj$, 次の手続き )

        手続きは ⇒ `~eventを発火する$( %~worker, `error$et )
        ◎ Queue a global task on the DOM manipulation task source given worker's relevant global object to fire an event named error at worker.
      2. %内側~設定群 用の`環境を破棄する手続き$() ◎ Run the environment discarding steps for inside settings.
      3. ~RET ◎ Abort these steps.
    2. %~worker を %~worker大域~scope に結付ける ◎ Associate worker with worker global scope.
    3. %内側~port ~LET `新たな~obj$( `MessagePort$I, %内側~設定群 の`~realm$enV ) ◎ Let inside port be a new MessagePort object in inside settings's realm.
    4. ~IF[ %共用か ~EQ ~F ]: ◎ If is shared is false, then:

      1. %内側~port の`~message~event~target$ ~SET %~worker大域~scope ◎ Set inside port's message event target to worker global scope.
      2. %~worker大域~scope の`内側~port$ ~SET %内側~port ◎ Set worker global scope's inside port to inside port.
    5. `~portを連絡する$( %外側~port, %内側~port ) ◎ Entangle outside port and inside port.
    6. %~worker大域~scope の`~worker所在~obj$ ~SET 新たな `WorkerLocation$I ~obj ◎ Create a new WorkerLocation object and associate it with worker global scope.
    7. %~worker大域~scope の監視を開始する: ◎ ↓

      • `孤立~workerは~close中^i ⇒ %~worker大域~scope が`保護され$なくなったときから`許可-可能$でなくなるときまで, %~worker大域~scope の`~close中か$wGを ~T に設定する ◎ Closing orphan workers: Start monitoring worker global scope such that no sooner than it stops being protected, and no later than it stops being permissible, worker global scope's closing flag is set to true.
      • `~workerは休止-中^i ⇒ %~worker大域~scope が次を満たすようになったときは、 満たさなくなるときまで, %~worker大域~scope 内の~scriptの実行を休止する ⇒ [ その`~close中か$wG ~EQ ~F ]~AND[ `休止-可能$である ] ◎ Suspending workers: Start monitoring worker global scope, such that whenever worker global scope's closing flag is false and it is suspendable, the user agent suspends execution of script in worker global scope until such time as either the closing flag switches to true or worker global scope stops being suspendable.
    8. %内側~設定群 の`実行は準備済みか$ ~SET ~T ◎ Set inside settings's execution ready flag.
    9. %~script に応じて:

      • `古典~script$ ⇒ `古典~scriptを走らす$( %~script )
      • `~module~script$ ⇒ `~module~scriptを走らす$( %~script )
      ◎ If script is a classic script, then run the classic script script. Otherwise, it is a module script; run the module script script.

      注記: 通例の[ 値を返す, 例外による失敗- ]に加えて,これは、 ~workerが`終了-$wKされたときも`尚早に中止され$得る。 ◎ In addition to the usual possibilities of returning a value or failing due to an exception, this could be prematurely aborted by the terminate a worker algorithm defined below.

    10. %外側~port の`~port~message~queue$を可能化する ◎ Enable outside port's port message queue.
    11. ~IF[ %共用か ~EQ ~F ] ⇒ ~workerの暗黙的な~port【 %内側~port 】の`~port~message~queue$を可能化する ◎ If is shared is false, enable the port message queue of the worker's implicit port.
    12. ~ELSE ⇒ `大域~taskを~queueする$( `~DOM操作~task~source$, %~worker大域~scope, 次の手続き )

      手続きは ⇒ `~eventを発火する$( %~worker大域~scope, `connect$et, `MessageEvent$I ) — 次のように初期化して ⇒# `data$m 属性 ~SET 空~文字列, `ports$m 属性 ~SET %内側~port のみを包含している新たな`凍結d配列$, `source$m 属性 ~SET %内側~port
      ◎ If is shared is true, then queue a global task on the DOM manipulation task source given worker global scope to fire an event named connect at worker global scope, using MessageEvent, with the data attribute initialized to the empty string, the ports attribute initialized to a new frozen array containing inside port, and the source attribute initialized to inside port.
    13. [ %~worker大域~scope に`関連な設定群~obj$を,`~sw~client$として結付けている `ServiceWorkerContainer$I ~obj ]の`~client~message~queue$を可能化する ◎ Enable the client message queue of the ServiceWorkerContainer object whose associated service worker client is worker global scope's relevant settings object.
    14. [ %内側~設定群 により指定される`担当の~event~loop$enV ]を破壊されるまで走らす ◎ Event loop: Run the responsible event loop specified by inside settings until it is destroyed.

      注記: `~event~loop$が走らす`~task$による,~eventの取扱いや~callbackの実行は、 ~workerが`終了-$wKされたときは,`尚早に中止され$得る。 ◎ The handling of events or the execution of callbacks by tasks run by the event loop might get prematurely aborted by the terminate a worker algorithm defined below.

      注記: この段における~workerの処理~modelは、 `~event~loop$処理~modelに述べられるとおり,[ `~close中か$wGが ~T にされた後の,~event~loopが破壊される ]まで残り続ける。 ◎ The worker processing model remains on this step until the event loop is destroyed, which happens after the closing flag is set to true, as described in the event loop processing model.

    15. %~worker大域~scope の`作動中な~timer群が成す~map$を`~clearする$map ◎ Clear the worker global scope's map of active timers.
    16. %~worker大域~scope の`~port~list$wGを成す ~EACH( %~port ) に対し ⇒ %~port の`連絡-$を断つ ◎ Disentangle all the ports in the list of the worker's ports.
    17. %~worker大域~scope の`所有者~集合$wGを空にする ◎ Empty worker global scope's owner set.

~UAが~workerを `終了-@wK させるときは、 当の~workerの~main~loop — すなわち,上で定義した “`~workerを走らす$” 処理~model — とは`並列的$に,次の手続きを走らすモノトスル: ◎ When a user agent is to terminate a worker, it must run the following steps in parallel with the worker's main loop (the "run a worker" processing model defined above):

  1. %~worker大域~scope ~LET 当の~workerの `WorkerGlobalScope$I ~obj ◎ ↓
  2. %~worker大域~scope の`~close中か$wG ~SET ~T ◎ Set the worker's WorkerGlobalScope object's closing flag to true.
  3. %~worker大域~scope に`関連な~agent$の`~event~loop$の`~task~queue$を成す ~EACH( `~task$ %~task ) に対し ⇒ %~task を処理することなく,破棄する【当の~task~queueから除去する】 ◎ If there are any tasks queued in the WorkerGlobalScope object's relevant agent's event loop's task queues, discard them without processing them.
  4. ~worker内で現在`走っている~scriptを中止する$ ◎ Abort the script currently running in the worker.
  5. ~IF[ %~worker大域~scope は `DedicatedWorkerGlobalScope$I ~objである (すなわち,~workerは専用~workerである) ] ⇒ ~workerの暗黙的な~port【 %~worker大域~scope の`内側~port$】の`~port~message~queue$を空にする ◎ If the worker's WorkerGlobalScope object is actually a DedicatedWorkerGlobalScope object (i.e. the worker is a dedicated worker), then empty the port message queue of the port that the worker's implicit port is entangled with.

~UAは、 次を満たす~workerが実行し続けているならば, それを`終了-$wKしてもヨイ ⇒ [ `作動中なため必要$ではない ]~AND[ `~close中か$wG ~EQ ~T ] ◎ User agents may invoke the terminate a worker algorithm when a worker stops being actively needed and the worker continues executing even after its closing flag was set to true.

10.2.5. 稼働時の~script~error

~workerの~scriptにおいて, ~catchされない稼働時の~script~errorが生じた場合、 それは[ それまでに~script~errorを取扱う間に生じたもの ]でないならば、 ~UAは,次を遂行することになる ⇒ `例外を報告する$( 当の~error, 当の~workerの `WorkerGlobalScope$I ~obj ) ◎ Whenever an uncaught runtime script error occurs in one of the worker's scripts, if the error did not occur while handling a previous script error, the user agent will report it for the worker's WorkerGlobalScope object.

10.2.6. ~workerの作成-法

10.2.6.1. `AbstractWorker^I ~mixin
interface mixin `AbstractWorker@I {
  attribute `EventHandler$I `onerror$mW;
};

`AbstractWorker$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 objects implementing the AbstractWorker interface:

`~event~handler$ ~event~handler~event型
`onerror@mW `error$et
10.2.6.2. ~worker用の~script設定群

`~workerの環境~設定群~objを設定しておく@ ~algoは、 所与の ( `~JS実行~文脈$ %実行~文脈, `環境~設定群~obj$ %外側~設定群, 数 %安全でない~worker作成~時刻 ) に対し: ◎ To set up a worker environment settings object, given a JavaScript execution context execution context, an environment settings object outside settings, and a number unsafeWorkerCreationTime:

  1. %継承した生成元 ~LET %外側~設定群 の`生成元$enV ◎ Let inherited origin be outside settings's origin.
  2. %realm ~LET %実行~文脈 の~Realm成分の値 ◎ Let realm be the value of execution context's Realm component.
  3. %~worker大域~scope ~LET %realm の`大域~obj$rM ◎ Let worker global scope be realm's global object.
  4. %設定群~obj ~LET 新たな`環境~設定群~obj$ — その各種~algoは、 次に従って定義される: ◎ Let settings object be a new environment settings object whose algorithms are defined as follows:

    • `~realm実行~環境$ ⇒ ~RET %実行~文脈 ◎ The realm execution context • Return execution context.
    • `~module~map$enV ⇒ ~RET %~worker大域~scope の`~module~map$wG ◎ The module map • Return worker global scope's module map.
    • `~API用~基底~URL$enV ⇒ ~RET %~worker大域~scope の`~URL$wG ◎ The API base URL • Return worker global scope's url.
    • `生成元$enV ⇒ ~RET [ 次が満たされるならば `不透明な生成元$ / ~ELSE_ %継承した生成元 ] ⇒ %~worker大域~scope の`~URL$wGの`~scheme$url ~EQ `data^l ◎ The origin • Return a unique opaque origin if worker global scope's url's scheme is "data", and inherited origin otherwise.
    • `非同一-~siteな先祖を有するか?$enV ⇒ ~RET ~IS[ %外側~設定群 の`非同一-~siteな先祖を有するか?$enV ~EQ ~T ]~OR[ %~worker大域~scope の`~URL$wGの`~scheme$url ~EQ `data^l ] ◎ The has cross-site ancestry • If outside settings's has cross-site ancestor is true, then return true. • If worker global scope's url's scheme is "data", then return true. • Return false.
    • `施策~容器$enV ⇒ ~RET %~worker大域~scope の`施策~容器$wG ◎ The policy container • Return worker global scope's policy container.
    • `非同一-生成元~能力は隔離されるか?$enV ⇒ ~RET %~worker大域~scope の`非同一-生成元~能力は隔離されるか$wG ◎ The cross-origin isolated capability • Return worker global scope's cross-origin isolated capability.
    • `時刻~起点$enV ⇒ ~RET `時刻を粗化する$( %安全でない~worker作成~時刻, %~worker大域~scope の`非同一-生成元~能力は隔離されるか$wG ) ◎ The time origin • Return the result of coarsening unsafeWorkerCreationTime with worker global scope's cross-origin isolated capability.
  5. %設定群~obj の ⇒# `~ID$enV ~SET 新たな一意かつ不透明な文字列, `作成時の~URL$enV ~SET %~worker大域~scope の`~URL$, `~top-level作成時の~URL$enV ~SET ~NULL, `~target閲覧~文脈$enV ~SET ~NULL, `作動中な~sw$enV ~SET ~NULL ◎ Set settings object's id to a new unique opaque string, creation URL to worker global scope's url, top-level creation URL to null, target browsing context to null, and active service worker to null.
  6. %設定群~obj の`~top-level生成元$enV ~SET %~worker大域~scope に応じて ⇒# `DedicatedWorkerGlobalScope$I ~objであるならば %外側~設定群 の`~top-level生成元$enV / ~ELSE_ `実装定義$な値 ◎ If worker global scope is a DedicatedWorkerGlobalScope object, then set settings object's top-level origin to outside settings's top-level origin. ◎ Otherwise, set settings object's top-level origin to an implementation-defined value.

    これを適正に定義している最新情報は、 `~client側~storage仕切り法@https://privacycg.github.io/storage-partitioning/$を見よ。 ◎ See Client-Side Storage Partitioning for the latest on properly defining this.

  7. %realm の `HostDefined^sl ~field ~SET %設定群~obj ◎ Set realm's [[HostDefined]] field to settings object.
  8. ~RET %設定群~obj ◎ Return settings object.
10.2.6.3. 専用~workerと `Worker^I ~interface
[Exposed=(Window,DedicatedWorker,SharedWorker)]
interface `Worker@I : `EventTarget$I {
  `Worker$mc((`TrustedScriptURL$I or USVString) %scriptURL, optional `WorkerOptions$I %options = {});

  undefined `terminate$mW();

  undefined `postMessage$mW(any %message, sequence<`object$> %transfer);
  undefined `~postMessageO$mW(any %message, optional `StructuredSerializeOptions$I %options = {});
};

dictionary `WorkerOptions@I {
  DOMString `name@mb = "";
  `WorkerType$I `type@mb = "classic";
  `RequestCredentials$I `credentials@mb = "same-origin"; /* 
`type$mb に `module^l を与えた場合に限り,利用される。
◎
credentials is only used if type is "module"
 */
};

enum `WorkerType@I { "classic", "module" };

`Worker$I includes `AbstractWorker$I;
`Worker$I includes `MessageEventTarget$I;
%worker = `new Worker(scriptURL [, options ])$m
新たな `Worker$I ~objを返す。 %scriptURL は~backgroundで~fetchされ, 実行され、 新たな大域~環境 %環境 が作成される。 返される %worker は、 %環境 への通信~channelを表現する。 ◎ Returns a new Worker object. scriptURL will be fetched and executed in the background, creating a new global environment for which worker represents the communication channel.

%options を成す: ◎ options can contain the following values:

  • `name$mb は、 %環境 の`名前$wGを定義するために利用できる — これは、 首に,~debug目的~用である。 ◎ name can be used to define the name of that global environment, primarily for debugging purposes.
  • `type$mb は、 その値を `module^l に設定することにより,[ %環境 を %scriptURL から~JS~moduleとして読込む ]ために利用できる。 ◎ type can be used to load the new global environment from scriptURL as a JavaScript module, by setting it to the value "module".
  • `credentials$mb は、 `type$mb が `module^l に設定された場合に限り,[ %scriptURL がどう~fetchされるかを指定する ]ために利用できる。 ◎ credentials can be used to specify how scriptURL is fetched, but only if type is set to "module".
%worker.`terminate()$mW
%worker に結付けられた大域~環境を中止する。 ◎ Aborts worker's associated global environment.
%worker.`postMessage(message, transfer)$mW
%worker.`~postMessageO(message [, options ])$mW
%message を~cloneして %worker の大域~環境へ伝送する。 [ %transfer / [ %options の `transfer$m ~member ]]には,一連の~objからなる~listを渡すことができ、 それらは~cloneされずに転送される。 ◎ Clones message and transmits it to worker's global environment. transfer can be passed as a list of objects that are to be transferred rather than cloned.

各 `Worker$I ~objには、 `外側~port@ が結付けられる — それは: ◎ Each Worker object has an associated outside port\

  • `MessagePort$I ~objである。 ◎ (a MessagePort).\
  • 当の~worker作成-時に設定しておかれる~channelの一部を成すが,公開されない。 ◎ This port is part of a channel that is set up when the worker is created, but it is not exposed.\
  • 当の `Worker$I ~objより先に~garbage収集されてはならない。 ◎ This object must never be garbage collected before the Worker object.
`terminate()@mW ~method手続きは ⇒ コレを結付けている~workerを`終了-$wKさせる ◎ The terminate() method steps are to terminate a worker given this's worker.

`postMessage(message, transfer)@mW ~method手続きは ⇒ ~RET コレの`外側~port$上の `postMessage$mMP ~method手続き( %message, %transfer )

`~postMessageO(message, options)@mW ~method手続きは ⇒ ~RET コレの`外側~port$上の `~postMessageO$mMP ~method手続き( %message, %options )

◎ The postMessage(message, transfer) and postMessage(message, options) methods on Worker objects act as if, when invoked, they immediately invoked the respective postMessage(message, transfer) and postMessage(message, options) on this's outside port, with the same arguments, and returned the same return value.

この~methodの %message 引数は有構造~dataでもよい: ◎ The postMessage() method's first argument can be structured data:

worker.postMessage({
   opcode: 'activate',
   device: 1938,
   parameters: [23, 102]
});

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

  1. %準拠な~script~URL ~LET `信用-済みな型に準拠な文字列を取得する$( ↓ ) ⇒# `TrustedScriptURL$I, コレに`関連な大域~obj$, %scriptURL, `Worker constructor^l, `script^l ◎ Let compliantScriptURL be the result of invoking the Get Trusted Type compliant string algorithm with TrustedScriptURL, this's relevant global object, scriptURL, "Worker constructor", and "script".
  2. %外側~設定群 ~LET コレに`関連な設定群~obj$ ◎ Let outsideSettings be this's relevant settings object.
  3. %~worker~URL ~LET `~URLを符号化法の下で相対的に構文解析する$( %準拠な~script~URL, %外側~設定群 ) ◎ Let workerURL be the result of encoding-parsing a URL given compliantScriptURL, relative to outsideSettings.

    注記: `blob$sc ~URLも含め,`同一-生成元$であれば どの~URLも利用できる。 `data$sc ~URLも利用できるが、 作成される~workerには`不透明な生成元$が伴われることになる。 ◎ Any same-origin URL (including blob: URLs) can be used. data: URLs can also be used, but they create a worker with an opaque origin.

  4. ~IF[ %~worker~URL ~EQ `失敗^i ] ⇒ ~THROW `SyntaxError$E ◎ If workerURL is failure, then throw a "SyntaxError" DOMException.
  5. %外側~port ~LET `新たな~obj$( `MessagePort$I, %外側~設定群 の`~realm$enV ) ◎ Let outsidePort be a new MessagePort in outsideSettings's realm.
  6. %外側~port の`~message~event~target$ ~SET コレ ◎ Set outsidePort's message event target to this.
  7. コレの`外側~port$ ~SET %外側~port ◎ Set this's outside port to outsidePort.
  8. %~worker ~LET コレ ◎ Let worker be this.
  9. この段は、 `並列的$に走らす ⇒ `~workerを走らす$( ↓ ) ⇒# %~worker, %~worker~URL, %外側~設定群, %外側~port, %options ◎ Run this step in parallel: • Run a worker given worker, workerURL, outsideSettings, outsidePort, and options.
10.2.6.4. 共用~workerと `SharedWorker^I ~interface
[Exposed=Window]
interface `SharedWorker@I : `EventTarget$I {
  `SharedWorker$mc((`TrustedScriptURL$I or USVString) %scriptURL, optional (DOMString or `WorkerOptions$I) %options = {});

  readonly attribute `MessagePort$I `port$mW;
};
`SharedWorker$I includes `AbstractWorker$I;
%sharedWorker = `new SharedWorker(scriptURL [, name ])$m
新たな `SharedWorker$I ~objを返す。 %scriptURL は~backgroundで~fetchされ, 実行され、 新たな大域~環境が作成される。 返される %sharedWorker は、 その大域~環境への通信~channelを表現する。 %name を利用すれば,その大域~環境の`名前$wGを定義できる。 ◎ Returns a new SharedWorker object. scriptURL will be fetched and executed in the background, creating a new global environment for which sharedWorker represents the communication channel. name can be used to define the name of that global environment.
%sharedWorker = `new SharedWorker(scriptURL [, options ])$m
新たな `SharedWorker$I ~objを返す。 %scriptURL は~backgroundで~fetchされ, 実行され、 新たな大域~環境 %環境 が作成される。 返される %sharedWorker は、 %環境 への通信~channelを表現する。 ◎ Returns a new SharedWorker object. scriptURL will be fetched and executed in the background, creating a new global environment for which sharedWorker represents the communication channel.

%options %options を成す: ◎ options can contain the following values:

  • `name$mb は、 %環境 の`名前$wGを定義するために利用できる。 ◎ name can be used to define the name of that global environment.
  • `type$mb は、 その値を `module^l に設定することにより,[ %環境 を %scriptURL から~JS~moduleとして読込む ]ために利用できる。 ◎ type can be used to load the new global environment from scriptURL as a JavaScript module, by setting it to the value "module".
  • `credentials$mb は、 `type$mb が `module^l に設定された場合に限り,[ %scriptURL がどう~fetchされるかを指定する ]ために利用できる。 ◎ credentials can be used to specify how scriptURL is fetched, but only if type is set to "module".

【!attempting to construct a shared worker with】 返される %sharedWorker が既存の共用~worker %既存の~worker と同じ[ `構築子~URL$wG, `名前$wG ]を伴うことになる場合、 %options の[ `type$mb / `credentials$mb ]に %既存の~worker の[ `種別$wG/`資格証$wG ]と合致しない値を与えていた場合には, %sharedWorker に向けて `error$et ~eventが発火され、 %sharedWorker は %既存の~worker には接続されなくなることに注意。 ◎ Note that attempting to construct a shared worker with options whose type, or credentials values mismatch those of an existing shared worker with the same constructor URL and name, will cause the returned sharedWorker to fire an error event and not connect to the existing shared worker.

%sharedWorker.`port$mW
%sharedWorker の `MessagePort$I ~objを返す。 それを利用して大域~環境と通信できる。 ◎ Returns sharedWorker's MessagePort object which can be used to communicate with the global environment.

~UAには `共用~worker管理器@ が結付けられる — 初期~時は、 次の結果とする ⇒ `新たな並列~queueを開始する$() ◎ A user agent has an associated shared worker manager which is the result of starting a new parallel queue.

注記: 単純にするため、 各~UAに結付けられる`共用~worker管理器$は 1 個だけとする。 実装は、 `生成元$ごとに 1 個ずつ利用して,同時並行性を高めることもできる — その相違は、 観測され得ないので。 ◎ Each user agent has a single shared worker manager for simplicity. Implementations could use one per origin; that would not be observably different and enables more concurrency.


各 `SharedWorker$I は、 `~port@sW を有する — それは、 当の~objの作成-時に,ある `MessagePort$I に設定される。 ◎ Each SharedWorker has a port, a MessagePort set when the object is created.

`port@mW 取得子~手続きは ⇒ ~RET コレの`~port$sW ◎ The port getter steps are to return this's port.

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

  1. %準拠な~script~URL ~LET `信用-済みな型に準拠な文字列を取得する$( ↓ ) ⇒# `TrustedScriptURL$I, コレに`関連な大域~obj$, %scriptURL, `SharedWorker constructor^l, `script^l ◎ Let compliantScriptURL be the result of invoking the Get Trusted Type compliant string algorithm with TrustedScriptURL, this's relevant global object, scriptURL, "SharedWorker constructor", and "script".
  2. ~IF[ %options は `DOMString^I である ] ⇒ %options ~SET 新たな `WorkerOptions$I 辞書 — その ⇒# `name$mb ~member ~SET %options, 他の~member ~SET 各自の既定~値 ◎ If options is a DOMString, set options to a new WorkerOptions dictionary whose name member is set to the value of options and whose other members are set to their default values.
  3. %外側~設定群 ~LET コレに`関連な設定群~obj$ ◎ Let outsideSettings be this's relevant settings object.
  4. %~URL~record ~LET `~URLを符号化法の下で相対的に構文解析する$( %準拠な~script~URL, %外側~設定群 ) ◎ Let urlRecord be the result of encoding-parsing a URL given compliantScriptURL, relative to outsideSettings.

    注記: `blob$sc ~URLも含め,`同一-生成元$であれば どの~URLも利用できる。 `data$sc ~URLも利用できるが、 作成される~workerには`不透明な生成元$が伴われることになる。 ◎ Any same-origin URL (including blob: URLs) can be used. data: URLs can also be used, but they create a worker with an opaque origin.

  5. ~IF[ %~URL~record ~EQ `失敗^i ] ⇒ ~THROW `SyntaxError^E ◎ If urlRecord is failure, then throw a "SyntaxError" DOMException.
  6. %外側~port ~LET `新たな~obj$( `MessagePort$I, %外側~設定群 の`~realm$enV ) ◎ Let outsidePort be a new MessagePort in outsideSettings's realm.
  7. コレの`~port$sW ~SET %外側~port ◎ Set this's port to outsidePort.
  8. %~call元は~secureな文脈か ~LET ~IS[ %外側~設定群 は`~secureな文脈$enVである ] ◎ Let callerIsSecureContext be true if outsideSettings is a secure context; otherwise, false.
  9. %外側~storage~key ~LET `非~storage目的~用に~storage~keyを得する$( %外側~設定群 ) ◎ Let outsideStorageKey be the result of running obtain a storage key for non-storage purposes given outsideSettings.
  10. %~worker ~LET コレ ◎ Let worker be this.
  11. `共用~worker管理器$に次の`手続きを~enqueueする$: ◎ Enqueue the following steps to the shared worker manager:

    1. %~worker大域~scope ~LET ~NULL ◎ Let workerGlobalScope be null.
    2. すべての `SharedWorkerGlobalScope$I ~objからなる~listを成す ~EACH( %~scope ) に対し: ◎ For each scope in the list of all SharedWorkerGlobalScope objects:

      1. %~worker~storage~key ~LET `非~storage目的~用に~storage~keyを得する$( %~scope に`関連な設定群~obj$ ) ◎ Let workerStorageKey be the result of running obtain a storage key for non-storage purposes given scope's relevant settings object.
      2. ~IF[ ~AND↓ ]… ◎ If all of the following are true:

        • ( %~worker~storage~key, %外側~storage~key ) は`同等な~storage~key$である ◎ workerStorageKey equals outsideStorageKey;
        • %~scope の`~close中か$wG ~EQ ~F ◎ scope's closing flag is false;
        • ( %~scope の`構築子~URL$wG, %~URL~record ) は`同等な~URL$である ◎ scope's constructor URL equals urlRecord; and
        • %~scope の`名前$wG ~EQ %options[ "`name$mb" ] ◎ scope's name equals options["name"],

        …ならば: ◎ then:

        1. %~worker大域~scope ~SET %~scope ◎ Set workerGlobalScope to scope.
        2. ~BREAK ◎ Break.

      注記: `data$sc ~URLは、 `不透明な生成元$を伴う~workerを作成することになる。 [ `構築子~生成元$wG, `構築子~URL$wG ]どちらも比較されるので、[ 同じ `data$sc ~URLを利用すれば, ある`生成元$の中で同じ `SharedWorkerGlobalScope$I ~objを取得できる ]が,`同一-生成元$の制約を素通りすることはできない。 ◎ data: URLs create a worker with an opaque origin. Both the constructor origin and constructor URL are compared so the same data: URL can be used within an origin to get to the same SharedWorkerGlobalScope object, but cannot be used to bypass the same origin restriction.

      【 この段には、 反復~順序が指定されていない — 条件を満たす %~scope が複数在る場合、 どれが選ばれるかは実装定義になる。 】

    3. ~IF[ %~worker大域~scope ~NEQ ~NULL ]: ◎ ↓

      1. ~IF[ ~UAは、[ %~worker大域~scope が表現する~workerと[ `~script$のうち[ その`設定群~obj$ ~EQ %外側~設定群 ]を満たすもの ]との間の通信 ]を許容しないよう環境設定されている ] ⇒ %~worker大域~scope ~SET ~NULL ◎ If workerGlobalScope is not null, but the user agent has been configured to disallow communication between the worker represented by the workerGlobalScope and the scripts whose settings object is outsideSettings, then set workerGlobalScope to null.

        注記: 例えば、 次のようなときが該当する ⇒ ~UAは開発~mode下にあり, そこでは 特定0の`~top-level辿可能$が 他のすべての~pageから隔離されていて、 その開発~mode下の~scriptから[ 通常の閲覧~modeで走っている~worker ]へ接続することは阻止されている。 ◎ For example, a user agent could have a development mode that isolates a particular top-level traversable from all other pages, and scripts in that development mode could be blocked from connecting to shared workers running in the normal browser mode.

      2. ~ELIF[ ~OR↓ ]… ◎ If workerGlobalScope is not null, and any of the following are true:

        • %~worker大域~scope の`種別$wG ~NEQ %options[ "`type$mb" ] ◎ workerGlobalScope's type is not equal to options["type"]; or
        • %~worker大域~scope の`資格証$wG ~NEQ %options[ "`credentials$mb" ] ◎ workerGlobalScope's credentials is not equal to options["credentials"]

        …ならば: ◎ then:

        1. `大域~taskを~queueする$( `~DOM操作~task~source$, %~worker に`関連な大域~obj$, 次の手続き ) ◎ Queue a global task on the DOM manipulation task source given worker's relevant global object to\

          手続きは ⇒ `~eventを発火する$( %~worker, `error$et ) ◎ fire an event named error at worker.
        2. ~RET ◎ Abort these steps.
    4. ~IF[ %~worker大域~scope ~NEQ ~NULL ]: ◎ If workerGlobalScope is not null:

      1. %内側~設定群 ~LET %~worker大域~scope に`関連な設定群~obj$ ◎ Let insideSettings be workerGlobalScope's relevant settings object.
      2. %~workerは~secureな文脈か ~LET ~IS[ %内側~設定群 は`~secureな文脈$enVである ] ◎ Let workerIsSecureContext be true if insideSettings is a secure context; otherwise, false.
      3. ~IF[ %~workerは~secureな文脈か ~NEQ %~call元は~secureな文脈か ]: ◎ If workerIsSecureContext is not callerIsSecureContext:

        1. `大域~taskを~queueする$( `~DOM操作~task~source$, %~worker に`関連な大域~obj$, 次の手続き ) ◎ Queue a global task on the DOM manipulation task source given worker's relevant global object to\

          手続きは ⇒ `~eventを発火する$( コレ, `error$et ) ◎ fire an event named error at worker.
        2. ~RET ◎ Abort these steps.
      4. コレを %~worker大域~scope に結付ける ◎ Associate worker with workerGlobalScope.
      5. %内側~port ~LET `新たな~obj$( `MessagePort$I, %内側~設定群 の`~realm$enV ) ◎ Let insidePort be a new MessagePort in insideSettings's realm.
      6. `~portを連絡する$( %外側~port, %内側~port ) ◎ Entangle outsidePort and insidePort.
      7. `大域~taskを~queueする$( `~DOM操作~task~source$, %~worker大域~scope, 次の手続き ) ◎ Queue a global task on the DOM manipulation task source given workerGlobalScope to\

        手続きは ⇒ `~eventを発火する$( %~worker大域~scope, `connect$et, `MessageEvent$I ) — 次のように初期化して ⇒# `data$m 属性 ~SET 空~文字列, `ports$m 属性 ~SET %内側~port のみを包含している新たな`凍結d配列$, `source$m 属性 ~SET %内側~port ◎ fire an event named connect at workerGlobalScope, using MessageEvent, with the data attribute initialized to the empty string, the ports attribute initialized to a new frozen array containing only insidePort, and the source attribute initialized to insidePort.
      8. %~worker大域~scope の`所有者~集合$wGに[ %外側~設定群 から与えられる,`関連な所有者として追加するもの$ ]を`付加する$set ◎ Append the relevant owner to add given outsideSettings to workerGlobalScope's owner set.
    5. ~ELSE ⇒ 次を`並列的$に走らす ⇒ `~workerを走らす$( ↓ ) ⇒# コレ, %~URL~record, %外側~設定群, %外側~port, %options ◎ Otherwise, in parallel, run a worker given worker, urlRecord, outsideSettings, outsidePort, and options.

10.3. ~workerから可用な~API

10.3.1. ~script/~libraryの~import法

`WorkerGlobalScope$I ~objの `importScripts(...urls)@m ~method手続きは: ◎ The importScripts(...urls) method steps are:

  1. %~URL文字列~群 ~LET « » ◎ Let urlStrings be « ».
  2. %urls を成す ~EACH( %~URL ) に対し: ◎ For each url of urls:

    1. %~URL文字列~群 に次の結果を`付加する$ ⇒ `信用-済みな型に準拠な文字列を取得する$( ↓ ) ⇒# `TrustedScriptURL$I, コレに`関連な大域~obj$, %~URL, `WorkerGlobalScope importScripts^l, `script^l ◎ Append the result of invoking the Get Trusted Type compliant string algorithm with TrustedScriptURL, this's relevant global object, url, "WorkerGlobalScope importScripts", and "script" to urlStrings.
  3. `~scriptを~worker大域~scopeの中へ~importする$( コレ, %~URL文字列~群 ) ◎ Import scripts into worker global scope given this and urlStrings.

`~scriptを~worker大域~scopeの中へ~importする@ ~algoは、 所与の ⇒# `WorkerGlobalScope$I ~obj %~worker大域~scope, `~scalar値~文字列$の`~list$ %~URL群, `~fetch~hookを遂行する~algo$ %~fetchを遂行する ~DF ε ◎終 に対し: ◎ To import scripts into worker global scope, given a WorkerGlobalScope object worker global scope, a list of scalar value strings urls, and an optional perform the fetch hook performFetch:

  1. ~IF[ %~worker大域~scope の`種別$wG ~EQ `module^l ] ⇒ ~THROW `TypeError^E ◎ If worker global scope's type is "module", throw a TypeError exception.
  2. %設定群~obj ~LET `現在の設定群~obj$ ◎ Let settings object be the current settings object.
  3. ~IF[ %~URL群 は空である ] ⇒ ~RET ◎ If urls is empty, return.
  4. %~URL~record群 ~LET « » ◎ Let urlRecords be « ».
  5. %~URL群 を成す ~EACH( %~URL文字列 ) に対し: ◎ For each url of urls:

    1. %~URL~record ~SET `~URLを符号化法の下で相対的に構文解析する$( %~URL文字列, %設定群~obj ) ◎ Let urlRecord be the result of encoding-parsing a URL given url, relative to settings object.
    2. ~IF[ %~URL~record ~EQ `失敗^i ] ⇒ ~THROW `SyntaxError^E ◎ If urlRecord is failure, then throw a "SyntaxError" DOMException.
    3. %~URL~record群 に %~URL~record を付加する ◎ Append urlRecord to urlRecords.
  6. %~URL~record群 を成す ~EACH( %~URL~record ) に対し: ◎ For each urlRecord of urlRecords:

    1. %~script ~LET `~workerが~importした古典~scriptを~fetchする$( %~URL~record, %設定群~obj, %~fetchを遂行する ) (この段は、 例外を投出し得る) ◎ Fetch a classic worker-imported script given urlRecord and settings object, passing along performFetch if provided. If this succeeds, let script be the result. Otherwise, rethrow the exception.
    2. `古典~scriptを走らす$( %~script, %~errorは再投出するか ~SET ~T ) ◎ Run the classic script script, with rethrow errors set to true.

      注記: ~scriptは、 次のいずれかが生じるまで走らすことになる ⇒# 普通に返った/ 構文解析-に失敗した/ 投出された例外を~catchしなかった/ ~workerが`終了-$wKされたため,`尚早に中止され$た ◎ script will run until it either returns, fails to parse, fails to catch an exception, or gets prematurely aborted by the terminate a worker algorithm defined above.

      [ ~scriptから例外が投出された / ~scriptは`尚早に中止され$た ]ときは 【普通に返らなかった場合】 ⇒ この手続きすべてを中止した上で、 ~call元~の~scriptにて,その[ 例外/中止- ]の処理を継続させる ◎ If an exception was thrown or if the script was prematurely aborted, then abort all these steps, letting the exception or aborting continue to be processed by the calling script.

注記: `Service Workers^cite `SW$r は、 自前の`~fetch~hookを遂行する~algo$を与えて この~algoを走らす仕様の例である。 ◎ Service Workers is an example of a specification that runs this algorithm with its own perform the fetch hook. [SW]

10.3.2. `WorkerNavigator^I ~interface

`WorkerGlobalScope$I ~interfaceの `navigator@m 取得子~手続きは、 ~UA(~client)の同一性と状態を表現する, `WorkerNavigator$I ~interfaceの~instanceを返す。 ◎ The navigator attribute of the WorkerGlobalScope interface must return an instance of the WorkerNavigator interface, which represents the identity and state of the user agent (the client):
[Exposed=Worker]
interface `WorkerNavigator@I {};
`WorkerNavigator$I includes `NavigatorID$I;
`WorkerNavigator$I includes `NavigatorLanguage$I;
`WorkerNavigator$I includes `NavigatorOnLine$I;
`WorkerNavigator$I includes `NavigatorConcurrentHardware$I;

10.3.3. `WorkerLocation^I ~interface

[Exposed=Worker]
interface `WorkerLocation@I {
  stringifier readonly attribute USVString `href$m;
  readonly attribute USVString `origin$m;
  readonly attribute USVString `protocol$m;
  readonly attribute USVString `host$m;
  readonly attribute USVString `hostname$m;
  readonly attribute USVString `port$m;
  readonly attribute USVString `pathname$m;
  readonly attribute USVString `search$m;
  readonly attribute USVString `hash$m;
};

各 `WorkerGlobalScope$I ~objは、 `~worker所在~obj@ を有する — それは、 ある `WorkerLocation$I ~objであり,初期~時は ε とする。 ◎ A WorkerLocation object has an associated WorkerGlobalScope object (a WorkerGlobalScope object).

【 これらの~objは、 一対一に対応する。 】【 初期~値 ε は、 ~~形式上のものであり,~accessされ得ない — `location$m の注記を見よ。 】

この節を通して、 `~URL@V は,[ `~worker所在~obj$として当の `WorkerLocation$I ~objを有している `WorkerGlobalScope$I ~obj ]の`~URL$wGを指すとする。 ◎ ↓

`href@m 取得子~手続きは ⇒ ~RET `~URLを直列化する$( `~URL$V ) ◎ The href getter steps are to return this's WorkerGlobalScope object's url, serialized.
`origin@m 取得子~手続きは ⇒ ~RET `生成元を直列化する$( `~URL$V の`生成元$url ) ◎ The origin getter steps are to return the serialization of this's WorkerGlobalScope object's url's origin.
`protocol@m 取得子~手続きは ⇒ ~RET 次を順に`連結する$ ⇒# `~URL$V の`~scheme$url, `:^l ◎ The protocol getter steps are to return this's WorkerGlobalScope object's url's scheme, followed by ":".

`host@m 取得子~手続きは:

  1. %~host ~LET `~URL$V の`~host$url
  2. ~IF[ %~host ~EQ ~NULL ] ⇒ ~RET 空~文字列
  3. %~host ~LET `~hostを直列化する$( %~host )
  4. %~port ~LET `~URL$V の`~port$url
  5. ~IF[ %~port ~EQ ~NULL ] ⇒ ~RET %~host
  6. %~port ~SET `整数を直列化する$( %~port )
  7. ~RET 次を順に`連結する$ ⇒# %~host, `:^l, %~port

◎ The host getter steps are: • Let url be this's WorkerGlobalScope object's url. • If url's host is null, return the empty string. • If url's port is null, return url's host, serialized. • Return url's host, serialized, followed by ":" and url's port, serialized.

`hostname@m 取得子~手続きは: ◎ The hostname getter steps are:

  1. %~host ~LET `~URL$V の`~host$url ◎ Let host be this's WorkerGlobalScope object's url's host.
  2. ~IF[ %~host ~EQ ~NULL ] ⇒ ~RET 空~文字列 ◎ If host is null, return the empty string.
  3. ~RET `~hostを直列化する$( %~host ) ◎ Return host, serialized.

`port@m 取得子~手続きは: ◎ The port getter steps are:

  1. %~port ~LET `~URL$V の`~port$url ◎ Let port be this's WorkerGlobalScope object's url's port.
  2. ~IF [ %~port ~EQ ~NULL ] ⇒ ~RET 空~文字列 ◎ If port is null, return the empty string.
  3. ~RET `整数を直列化する$( %~port ) ◎ Return port, serialized.
`pathname@m 取得子~手続きは ⇒ ~RET `~URL~pathを直列化する$( `~URL$V ) ◎ The pathname getter steps are to return the result of URL path serializing this's WorkerGlobalScope object's url.

`search@m 取得子~手続きは: ◎ The search getter steps are:

  1. %~query ~LET `~URL$V の`~query$url ◎ Let query be this's WorkerGlobalScope object's url's query.
  2. ~IF[ %~query ~IN { ~NULL, 空~文字列 } ] ⇒ ~RET 空~文字列 ◎ If query is either null or the empty string, return the empty string.
  3. ~RET 次を順に`連結する$ ⇒# `?^l, %~query ◎ Return "?", followed by query.

`hash@m 取得子~手続きは: ◎ The hash getter steps are:

  1. %素片 ~LET `~URL$V の`素片$url ◎ Let fragment be this's WorkerGlobalScope object's url's fragment.
  2. ~IF[ %素片 ~IN { ~NULL, 空~文字列 } ] ⇒ ~RET 空~文字列 ◎ If fragment is either null or the empty string, return the empty string.
  3. ~RET 次を順に`連結する$ ⇒# `#^l, %素片 ◎ Return "#", followed by fragment.