Web Workers

10. Web Workers

10.1. 序論

10.1.1. 視野

~INFORMATIVE

この仕様は、他の~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ごとの記憶域~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. 例

~INFORMATIVE

~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

~INFORMATIVE

~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>

`Worker()$m 構築子の~callにより,~workerが作成され、[ その~workerを表現し, その~workerと通信する, `Worker$I ~obj ]が返される。 ~objの `onmessage$mW ~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節)が、(~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で見る ◎ View this example online.

10.1.2.2. ~JS~moduleを~workerとして利用する

~INFORMATIVE

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

  • ~JS `import^c 文を利用して他の~moduleを取込む能
  • 既定で~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.

そのような~moduleに基づく~workerは、非同一生成元~内容に関して,~classic~workerと異なる制約に従うことに注意。 ~classic~workerと違って,~module~workerは、その~scriptが`~CORS~protocol$を利用して公開されている限り,非同一生成元~scriptを利用して~instance化できる。 加えて、 `importScripts()$m ~methodは,~module~workerの内側では自動的に失敗することになるので、一般に,~JS `import^c 文の方が良い~~選択になる。 ◎ Note that such module-based workers follow different restrictions regarding cross-origin content, compared to classic workers. Unlike classic workers, module workers can be instantiated using a cross-origin script, as long as that script is exposed using the CORS protocol. Additionally, the importScripts() method will automatically fail inside module workers; the JavaScript import statement is generally a better choice.

この例では、~main文書が,~main~threadの外で画像~操作を行う~workerを利用する。 それは、別の~moduleから利用される~filterを取込む。 ◎ 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>

<canvas id="output"></canvas>

<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 = () => {
      %output.innerHTML = "";

      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.appendChild(%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 を取込む: ◎ 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で見る ◎ View this example online.

10.1.2.3. 共用~worker序論

~INFORMATIVE

この節では、 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.

この最初の例では、利用者がどのようにして~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で見る ◎ 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で見る ◎ 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 browsing context.

外縁~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で見る ◎ View this example online.

10.1.2.4. 共用~workerの利用による状態の共有-

~INFORMATIVE

次の例では、同じマップを~~表示する複数の~window(~viewer)を開けるようになっている。 単独の~workerが すべての~viewerを束ねる形で、すべての~windowが同じマップ情報を共有する。 それぞれの~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: 単独の~message処理~関数の代わりに、この~codeでは,それぞれが~messageに関連するのかどうかの~~簡単な検査を遂行するような,複数の~event~listenerを付け加えている。 この例では,さほど大きな相違は生じないが、幾人かの作者~達が協同する中で,~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は、複数の接続を待ち受けるために, `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を受信したときには、 2 つの間に直接~接続が設定しておかれ、~workerがすべての~messageを代理しなくとも, 2 つの~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で見る ◎ View this example online.

10.1.2.5. 委譲

~INFORMATIVE

~multi~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例: ~multi~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で見る ◎ View this example online.

10.1.2.6. ~libraryの提供-法

~INFORMATIVE

次の 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 cyphertext
渡された~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 cyphertext. The user can close the port when it is done encrypting content.
所与の ( 暗号文, 私用鍵 ) 対応する平文を返す ◎ Given a cyphertext 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 cyphertext, 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が共用/ 専用のどちらとして利用されていても~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が共用/ 専用のどちらとして利用されていても~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で見る 。 ◎ View this example online.

10.1.3. ~tutorial

10.1.3.1. 専用~workerの作成-法

~INFORMATIVE

~workerを作成するためには~JS~fileの~URLを要する。 その~fileの~URLのみを引数として `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');

`~classic~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.js', { type: "module" });

10.1.3.2. 専用~workerとの通信-法

~INFORMATIVE

専用~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$mW `~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

~INFORMATIVE

共用~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の作成には、 `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を通して行う。 `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
 */
};

【この訳に固有の表記規約】

この訳の~algoや定義の記述に利用されている各種記号( ~LET, 此れ, ~IF, ~THROW 等々)の意味や定義の詳細は、~SYMBOL_DEF_REFを~~参照されたし。

10.2. 基盤

~workerは、専用~workerと共用~workerの 2 つに大別される。 専用~workerは、作成-時にその作成元に~linkされるが、~message~portを利用すれば,他の閲覧文脈や~workerに向けても通信できる。 一方で,共用~workerは、名前を持ち,その作成-後に それへの参照を得ておけば、同じ`生成元$上で走っているどの~scriptとも通信できる。 ◎ There are 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.

10.2.1. 大域~scope

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

【 すなわち,同じ~workerが、その内側で走っている~scriptに公開する `WorkerGlobalScope$I ~obj(大域~scope)と, その~workerを外側から利用する~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;
  void `importScripts$m(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として~~働く ⇒ `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 (空)
[ `Document$I / `WorkerGlobalScope$I ]~objの`集合$。 この~workerを[ 作成する/得る ]ときに拡充される。 ◎ A WorkerGlobalScope object has an associated owner set (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 accomodate SharedWorkerGlobalScope objects.
`~worker集合@wG (空)
`WorkerGlobalScope$I ~objの`集合$。 この~workerが更なる~workerを[ 作成する/得る ]ときに拡充される。 ◎ A WorkerGlobalScope object has an associated worker set (a set of WorkerGlobalScope objects). It is initially empty and populated when the worker creates or obtains further workers.
`種別@wG
次のいずれか ⇒ `classic^l / `module^l ◎ A WorkerGlobalScope object has an associated type ("classic" or "module"). It is set during creation.
`~url@wG( ~NULL )
~NULL または `~URL$ ◎ A WorkerGlobalScope object has an associated url (null or a URL). It is initially 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 of WorkerGlobalScope.\

  • `専用~worker$の~instanceに対しては、単純に開発者が給する名前であり,ほぼ~debug目的に限り有用になる。 ◎ For DedicatedWorkerGlobalScope instances, it is simply a developer-supplied name, useful mostly for debugging purposes.\
  • `SharedWorkerGlobalScope$I ~instanceに対しては、共通の共用~workerへの参照を, `SharedWorker$m 構築子を介して得れるようにする。 ◎ For SharedWorkerGlobalScope instances, it allows obtaining a reference to a common shared worker via the SharedWorker() constructor.\
  • `ServiceWorkerGlobalScope$I ~objに対しては、用をなさない(そのため、~JS~APIを通して公開されることもない)。 ◎ For ServiceWorkerGlobalScope objects, it doesn't make sense (and as such isn't exposed through the JavaScript API at all).
`~HTTPS状態@wG( `none^l )
`~HTTPS状態~値$ ◎ A WorkerGlobalScope object has an associated HTTPS state (an HTTPS state value). It is initially "none".
`~referrer施策@wG(空~文字列)
`~referrer施策$ ◎ A WorkerGlobalScope object has an associated referrer policy (a referrer policy). It is initially the empty string.
`~CSP~list@wG(空~list)
`~CSP~obj$の~list ◎ A WorkerGlobalScope object has an associated CSP list. It is initially an empty list.
`~module~map@wG(空)
`~module~map$ ◎ A WorkerGlobalScope object has an associated module map. It is a module map, initially empty.
%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...)$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
取得子は、此れを返さ~MUST。 ◎ The self attribute must return the WorkerGlobalScope object itself.
`location@m
取得子は、 `WorkerLocation$I ~objであって, [ その`~worker大域~scope$ ~EQ 此れ ]なるものを返さ~MUST。 ◎ The location attribute must return the WorkerLocation object whose associated WorkerGlobalScope object is the WorkerGlobalScope object.
`WorkerLocation$I ~objが作成されるのは, `WorkerGlobalScope$I ~objより後になるが、それは~scriptからは観測し得ないので,問題にはならない。 ◎ 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され~MUST: ◎ 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;

  void `postMessage$m(any %message, optional sequence<`object$> %transfer = []);

  void `close$m();

  attribute `EventHandler$I `onmessage$m;
  attribute `EventHandler$I `onmessageerror$m;
};

各 `DedicatedWorkerGlobalScope$I ~objには、 `暗黙的な~port@ が結付けられているかのように,動作し~MUST。 それは, `MessagePort$I ~objであり、~worker作成-時に設定-済みの~channelの一部を成すが,公開されることはない。 この~objは、決して `DedicatedWorkerGlobalScope$I ~objより先に~garbage収集されてはならない。 ◎ DedicatedWorkerGlobalScope objects act as if they had an implicit MessagePort associated with them. This port is part of a channel that is set up when the worker is created, but it is not exposed. This object must never be garbage collected before the DedicatedWorkerGlobalScope object.

`暗黙的な~port$から受信されるすべての~messageは、即時に `DedicatedWorkerGlobalScope$I ~objに渡され~MUST。 ◎ All messages received by that port must immediately be retargeted at the DedicatedWorkerGlobalScope object.

%dedicatedWorkerGlobal . `name$m
%dedicatedWorkerGlobal の`名前$wG — すなわち, `Worker()$m 構築子に与えた値 — を返す。 主に、~debug時に有用になる。 ◎ Returns dedicatedWorkerGlobal's name, i.e. the value given to the Worker constructor. Primarily useful for debugging.
%dedicatedWorkerGlobal . `postMessage(message [, transfer ])$mW
~messageを~cloneして,それを %dedicatedWorkerGlobal に結付けられている `Worker$I ~objへ伝送する。 %transfer に、~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
取得子は、此れの`名前$wGを返さ~MUST。 この値は、 `Worker$I 構築子を用いて~workerに与えた名前を表現する — これは主に、~debug目的に利用される。 ◎ The name attribute must return the DedicatedWorkerGlobalScope object's name. Its value represents the name given to the worker using the Worker constructor, used primarily for debugging purposes.
`postMessage()@m
被呼出時には、それが即時に,此れの`暗黙的な~port$上の`同じ名前の~method$を同じ引数で呼出して, 同じ値を返したかのように,動作し~MUST。 ◎ The postMessage() method on DedicatedWorkerGlobalScope objects must act as if, when invoked, it immediately invoked the method of the same name on the port, with the same arguments, and returned the same return value.

所与の %workerGlobal に対し, `~workerを~close@ するときは、次の手続きを走らす: ◎ To close a worker, given a workerGlobal, run these steps:

  1. %workerGlobal の`~eventloop$の`~task~queue$に追加された`~task$は、すべて破棄する ◎ Discard any tasks that have been added to workerGlobal's event loop's task queues.
  2. %workerGlobal の`~closing~flag$i ~SET ~ON (これにより、~taskがそれ以上~queueされることはなくなる。) ◎ Set workerGlobal's closing flag to true. (This prevents any further tasks from being queued.)
`close()@m
被呼出時には、此れを与える下で,`~workerを~close$し~MUST。 ◎ The close() method, when invoked, must close a worker with this DedicatedWorkerGlobalScope object.

`DedicatedWorkerGlobalScope$I ~interfaceを実装する~objにおいては、次の`~event~handler$(および,それらに対応する`~event~handler ~event型$)が`~event~handler~IDL属性$として~supportされ~MUST: ◎ 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 DedicatedWorkerGlobalScope interface:

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

【`~app-cache関連$の記述(この訳では省略する)。】 ◎ For the purposes of the application cache networking model, a dedicated worker is an extension of the cache host from which it was created.

10.2.1.3. 共用~workerと `SharedWorkerGlobalScope^I ~interface

[Global=(Worker,SharedWorker),Exposed=SharedWorker]
interface `SharedWorkerGlobalScope@I : `WorkerGlobalScope$I {
  [Replaceable] readonly attribute DOMString `~nameS$m;

  void `~closeS$m();

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

各 `SharedWorkerGlobalScope$I ~objには、[ `構築子~生成元@wG , `構築子~url@wG ]が結付けられる。 これらは、~objの作成-時に`~workerを走らす$~algoにて初期化される。 ◎ A SharedWorkerGlobalScope object has an associated constructor origin, and constructor url. 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 — すなわち, `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
取得子は、此れの`名前$wGを返さ~MUST。 この値は、 `SharedWorker$I 構築子を用いて~workerへの参照を得るときに利用できる名前を表現する。 ◎ The name attribute must return the SharedWorkerGlobalScope object's name. Its value represents the name that can be used to obtain a reference to the worker using the SharedWorker constructor.
`~closeS()@m
被呼出時には、此れを与える下で,`~workerを~close$し~MUST。 ◎ The close() method, when invoked, must close a worker with this SharedWorkerGlobalScope object.

`SharedWorkerGlobalScope$I ~interfaceを実装する~objにおいては、次の`~event~handler$(および,それらに対応する`~event~handler ~event型$)が`~event~handler~IDL属性$として~supportされ~MUST: ◎ 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. ~eventloop

各 `WorkerGlobalScope$I ~objは、次のものを持つ: ◎ ↓

`~eventloop@

この`~eventloop$xは:

  • `互いに関係するかつ生成元も類似する閲覧文脈~群$に対し定義されるそれとは別々の,異なる`~eventloop$xであり、`閲覧文脈$には結付けられない。
  • その`~task~queue$内にあり得る`~task$は、[ ~event, ~callback, ~networking活動 ]に限られる。
  • `~workerを走らす$~algoにより作成される。
◎ Each WorkerGlobalScope object has a distinct event loop, separate from those used by units of related similar-origin browsing contexts. This event loop has no associated browsing context, and its task queues only have events, callbacks, and networking activity as tasks. These event loops are created by the run a worker algorithm.
`~closing~flag@i
初期~時には ~OFF にされ~MUST。 下の処理~model節の~algoにより, ~ON にされ得る。 ◎ Each WorkerGlobalScope object also has a closing flag, which must initially be false, but which can get set to true by the algorithms in the processing model section below.
~ON にされたときは、`~eventloop$の`~task~queue$に追加される それ以降の`~task$は,破棄され~MUST(~queue内にすでにある~taskは、特に指定されない限り,影響されない)。 実質的には、~ON になったら,~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や`閲覧文脈$と通信する。 ◎ Workers communicate with other workers and with browsing contexts 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 のみを所有している 【 %P の`所有者$ ~EQ %G に`関連する設定群~obj$ ~NEQ %Q の`所有者$ 】 ] ◎ 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.\
  • `専用~worker$の事例では、この~listは`暗黙的な~port$も含む。 【前~項の条件を満たす限り】 ◎ This list includes the implicit MessagePort in the case of dedicated workers.

`文書$が`破棄-$されたときは、それを`包含-$している,各 `WorkerGlobalScope$I ~objの`所有者~集合$wGからも`除去-$setされ~MUST。 ◎ Whenever a Document object is discarded, it must be removed from the owner set of each WorkerGlobalScope object whose set contains that Document object.

所与の`環境~設定群~obj$ %O の下で~workerを[ 作成する/得る ]ときに, `関連する所有者として追加するもの@ は、[ %O により指定される`大域~obj$enV %G の型 ]に応じて[ `WorkerGlobalScope$I (すなわち,入子の~workerを作成している)ならば %G / `Window$I ならば %G により指定される`担当の文書$enV ]になる。 ◎ 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. If o specifies a global object that is a WorkerGlobalScope object (i.e., if we are creating a nested worker), then the relevant owner is that global object. Otherwise, o specifies a global object that is a Window object, and the relevant owner is the responsible document specified by o.


~workerは、次を満たしている間は, `許可可能@ ( permissible )とされる ⇒ その `WorkerGlobalScope$I %G の`所有者~集合$wG %S は`空$でない ~OR 次のいずれも満たされる: ◎ A worker is said to be a permissible worker if its WorkerGlobalScope's owner set is not empty or:

  • %S は、~UAにより定義される短い~timeout値を超えて空であり続けることはない。 ◎ its owner set has been empty for no more than a short user-agent-defined timeout value,
  • %G は `SharedWorkerGlobalScope$I ~objである(すなわち,~workerは共用~workerである) ◎ its WorkerGlobalScope object is a SharedWorkerGlobalScope object (i.e., the worker is a shared worker), and
  • ~UAには、`文書$が`完全に読込まれて$はいない`閲覧文脈$がある。 ◎ the user agent has a browsing context whose Document object is not completely loaded.

注記: 上の定義の 2 番目の項は、読込まれている短い間に,~pageが共用~workerに再び繋がろうとしている下でも、共用~workerが生存できるようにする。 これを利用すれば,~UAは、利用者が ある~siteの中で~pageから~pageへ~navigateするときに,その~siteが利用している共用~workerを再始動する~costを避けれるようになる。 ◎ The second part of this definition allows a shared worker to survive for a short time while a page is loading, in case that page is going to contact the shared worker again. This can be used by user agents as a way to avoid the cost of restarting a shared worker used by a site when the user is navigating from page to page within that site.

~workerは、次を満たしている間は, `作動中のため必要@ ( active needed )とされる ⇒ その`所有者~集合$wG内に[ `全部的に作動中$である`文書$ / `作動中のため必要$である~worker ]がある ◎ A worker is said to be an active needed worker if any its owners are either Document objects that are fully active or active needed workers.

~workerは、次を満たしている間は, `保護され@ ている( protected )とされる: ◎ A worker is said to be a protected worker if\

  • `作動中のため必要$である ~AND ◎ it is an active needed worker and\
  • 次のいずれかが満たされる:

    • 未終了の~timerがある。
    • ~database~transactionを持つ。
    • ~network接続を持つ。
    • `~port~list$wGは空でない。
    • その `WorkerGlobalScope$I は実際に `SharedWorkerGlobalScope$I ~objである(すなわち,~workerは共用~workerである)
    ◎ either it has outstanding timers, database transactions, or network connections, or its list of the worker's ports is not empty, or its WorkerGlobalScope is actually a SharedWorkerGlobalScope object (i.e. the worker is a shared worker).

~workerは、次を満たしている間は, `休止可能@ ( suspendable )とされる ⇒ `作動中のため必要$でない ~AND `許可可能$ ◎ A worker is said to be a suspendable worker if it is not an active needed worker but it is a permissible worker.

10.2.4. 処理~model

~UAは、ある~script用の `~workerを走らす@ ときは、所与の ⇒# %~worker ( `Worker$I / `SharedWorker$I ~obj ), %url ( `~URL$ ), %外側~設定群 ( `環境~設定群~obj$ ), %外側~port ( `MessagePort$I ~obj ), %options ( `WorkerOptions$I 辞書 ) ◎終 に対し,次の手続きを走らせ~MUST: ◎ 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. 別々の並列~実行~環境(すなわち,別の~threadや~processまたはそれに等価なもの)を作成した上で、この手続きの以下の部分をその文脈の下で走らす。 ◎ Create a separate parallel execution environment (i.e. a separate thread or process or equivalent construct), and run the rest of these steps in that context.

    計時~APIの目的においては,これが~workerの `公式的な作成~時点@ になる。 ◎ For the purposes of timing APIs, this is the official moment of creation of the worker.

  2. %共用is ~LET [ %~worker は `SharedWorker$I ~objであるならば ~T / ~ELSE_ ~F ] ◎ Let is shared be true if worker is a SharedWorker object, and false otherwise.
  3. %所有者 ~LET %外側~設定群 から与えられる,`関連する所有者として追加するもの$ ◎ Let owner be the relevant owner to add given outside settings.
  4. %親~worker大域~scope ~LET ~NULL ◎ Let parent worker global scope be null.
  5. ~IF[ %所有者 は `WorkerGlobalScope$I ~objである(すなわち、この手続きは入子の~workerを作成している) ] ⇒ %親~worker大域~scope ~SET %所有者 ◎ If owner is a WorkerGlobalScope object (i.e., we are creating a nested worker), then set parent worker global scope to owner.
  6. 次のように~custom化する下で,~JSの `InitializeHostDefinedRealm()$jA 抽象演算を~callする: ◎ Call the JavaScript InitializeHostDefinedRealm() abstract operation with the following customizations:

    • %~worker大域~scope (大域~obj用) ~LET %共用is に応じて[ ~T ならば 新たな `SharedWorkerGlobalScope$I ~obj / ~F ならば 新たな `DedicatedWorkerGlobalScope$I ~obj ] ◎ For the global object, if is shared is true, create a new SharedWorkerGlobalScope object. Otherwise, create a new DedicatedWorkerGlobalScope object. Let worker global scope be the created object.
    • %~realm実行~環境 ~LET 作成された`~JS実行~文脈$ ◎ Let realm execution context be the created JavaScript execution context.
  7. %内側~設定群 ~LET `~workerの環境~設定群~objを設定しておく$( %~realm実行~環境, %外側~設定群 ) ◎ Set up a worker environment settings object with realm execution context and outside settings, and let inside settings be the result.
  8. %~worker大域~scope の`名前$wG ~SET %options の `name^m ~memberの値 ◎ Set worker global scope's name to the value of options's name member.
  9. ~IF[ %共用is ~EQ ~T ] ⇒ %~worker大域~scope の ( `構築子~生成元$wG, `構築子~url$wG ) ~SET ( %外側~設定群 の`生成元$enV, %url ) ◎ 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.
  10. %行先 ~LET [ %共用is ~EQ ~T ならば `sharedworker^l / ~ELSE_ `worker^l ] ◎ Let destination be "sharedworker" if is shared is true, and "worker" otherwise.
  11. %options の `type^m ~memberの値に応じて,次に従って~scriptを得る: ◎ Obtain script by switching on the value of options's type member:

    `classic^l
    `~worker用~classic~scriptを~fetchする$( %~url, %外側~設定群, %行先, %内側~設定群 ) ◎ Fetch a classic worker script given url, outside settings, destination, and inside settings.
    `module^l
    `~worker用~module~script~graphを~fetchする$( %~url, %外側~設定群, %行先, %options の `credentials^m ~memberの値, %内側~設定群 ) ◎ Fetch a module worker script graph given url, outside settings, destination, the value of the credentials member of options, and inside settings.

    いずれの場合も,`~fetchを遂行する$ときは、所与の ( %要請, `~top-level内~flag$V ) に対し,[ `~top-level内~flag$V ~EQ ~ON ]ならば,次の手続きを遂行する: ◎ In both cases, to perform the fetch given request, perform the following steps if the is top-level flag is set:

    1. %要請 の`予約済み~client$rq ~SET %内側~設定群 ◎ Set request's reserved client to inside settings.
    2. %要請 を`~fetch$する — ~fetchし終えるまで非同期に待機した上で,手続きの以降を[ 結果の`応答$ %応答 に対し ~fetchの`応答を処理する$ ]一部として走らす ◎ Fetch request, and asynchronously wait to run the remaining steps as part of fetch's process response for the response response.
    3. %~worker大域~scope の`~url$wG ~SET %応答 の `~url$rs ◎ Set worker global scope's url to response's url.
    4. %~worker大域~scope の`~HTTPS状態$wG ~SET %応答 の`~HTTPS状態$rs ◎ Set worker global scope's HTTPS state to response's HTTPS state.
    5. %~worker大域~scope の`~referrer施策$wG ~SET %応答 の `Referrer-Policy^h ~headerを構文解析- した結果 ◎ Set worker global scope's referrer policy to the result of parsing the `Referrer-Policy` header of response.
    6. `大域~objの~CSP~listを初期化する$( %~worker大域~scope, %応答 ) `CSP$r ◎ Execute the Initialize a global object's CSP list algorithm on worker global scope and response. [CSP]
    7. %応答 を結果として`非同期に完了-$する ◎ Asynchronously complete the perform the fetch steps with response.
  12. 前~段が %~script を結果として`非同期に完了-$するまで待機した上で:

    1. ~IF[ %~script ~EQ ~NULL ]:

      1. 次を走らす`~taskを~queueする$ ⇒ %~worker に向けて,名前 `error$et の`~eventを発火する$
      2. ~RET
    ◎ If the algorithm asynchronously completes with null, queue a task to fire an event named error at worker, and return. Otherwise, continue the rest of these steps after the algorithm's asynchronous completion, with script being the asynchronous completion value.
  13. %~worker を %~worker大域~scope に結付ける ◎ Associate worker with worker global scope.
  14. %内側~port ~LET `~MessagePort~objを作成する$( %内側~設定群 ) ◎ Create a new MessagePort object whose owner is inside settings. Let inside port be this new object.
  15. %内側~port を %~worker大域~scope に結付ける ◎ Associate inside port with worker global scope.
  16. `~portを連絡する$( %外側~port, %内側~port ) ◎ Entangle outside port and inside port.
  17. %~worker大域~scope の`所有者~集合$wGに %所有者 を`付加する$set ◎ Append owner to worker global scope's owner set.
  18. ~IF[ %親~worker大域~scope ~NEQ ~NULL ] ⇒ %親~worker大域~scope の`~worker集合$wGに %~worker大域~scope を`付加する$set ◎ If parent worker global scope is not null, then append worker global scope to parent worker global scope's worker set.
  19. %~worker大域~scope の`種別$wG ~SET %options の `type^m ~memberの値 ◎ Set worker global scope's type to the value of the type member of options.
  20. 新たな `WorkerLocation$I ~objを作成して,それに %~worker大域~scope を結付ける ◎ Create a new WorkerLocation object and associate it with worker global scope.
  21. ~workerの監視を開始する: ◎ ↓

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

    `~classic~script$である
    `~classic~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が終了され$たときも`尚早に中止され$得る。 ◎ 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.

  24. %外側~port の`~port~message~queue$を可能化する ◎ Enable outside port's port message queue.
  25. ~IF[ %共用is ~EQ ~F ] ⇒ ~workerの暗黙的な~portの`~port~message~queue$を可能化する ◎ If is shared is false, enable the port message queue of the worker's implicit port.
  26. ~IF[ %共用is ~EQ ~T ] ⇒ `~DOM操作~task源$から,次を走らす`~taskを~queueする$ ⇒ %~worker大域~scope に向けて,次のように初期化された`~eventを発火する$ ⇒# `MessageEvent$I ~interfaceを利用する, 名前 `connect$et, `data$m 属性 ~SET 空~文字列, `ports$m 属性 ~SET %内側~port のみを含む新たな`凍結~配列$, `source$m 属性 ~SET %内側~port ◎ If is shared is true, then queue a task, using the DOM manipulation task source, 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.

  27. [ %~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.
  28. [ %内側~設定群 により指定される`担当の~eventloop$enV ]を,破壊されるまで走らす ◎ Event loop: Run the responsible event loop specified by inside settings until it is destroyed.

    注記: `~eventloop$が走らす`~task$による,~eventの取扱いや~callbackの実行は、`~workerが終了され$たときは,`尚早に中止され$得る。 ◎ 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は、`~eventloop$処理~modelに述べられるように,[ `~closing~flag$iが ~ON にされた後の,~eventloopが破壊される ]まで、残り続ける。 ◎ 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.

  29. %~worker大域~scope にて`作動中の~timerの~list$を空にする ◎ Empty the worker global scope's list of active timers.
  30. %~worker大域~scope の`~port~list$wG内のすべての~portに対し、それぞれの`連絡-$を~~解く ◎ Disentangle all the ports in the list of the worker's ports.
  31. %~worker大域~scope の`所有者~集合$wGを空にする ◎ Empty worker global scope's owner set.

~UAが `~workerを終了させ@ るときは、~workerの~main~loop — すなわち,上で定義した “`~workerを走らす$” 処理~model — とは`並列的$に,次の手続きを走らせ~MUST: ◎ 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 の`~closing~flag$i ~SET ~ON ◎ Set the worker's WorkerGlobalScope object's closing flag to true.
  3. %~worker大域~scope の`~eventloop$の`~task~queue$内にある`~task$は、処理せずに,破棄する ◎ If there are any tasks queued in the WorkerGlobalScope object's event loop's task queues, discard them without processing them.
  4. ~worker内で現在`走っている~scriptを中止-$する ◎ Abort the script currently running in the worker.
  5. %~worker大域~scope が実際には `DedicatedWorkerGlobalScope$I ~objである場合(すなわち~workerは専用~worker)、 ~workerの暗黙的な~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が[ `作動中のため必要$でなくなっていて,`~closing~flag$iが ~ON にされた後でも実行し続けている ]ときは、`~workerを終了させ$ても~MAY。 ◎ User agents may invoke the terminate a worker algorithm when a worker stops being an active needed worker and the worker continues executing even after its closing flag was set to true.


上で言及した~taskの`~task源$は、`~DOM操作~task源$とする。 ◎ The task source for the tasks mentioned above is the DOM manipulation task source.

10.2.5. 稼働時の~script~error

~workerの~scriptのいずれかにおいて,~catchされない稼働時の~script~errorが生じた場合、その~errorが以前の~script~errorの取扱い時に生じたものでないならば,~UAは 次をし~MUST: ◎ 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 must\

  • `WorkerGlobalScope$I ~objを target に、~errorが生じた位置(行~番号と列~番号)を伴う,当の`~script$の`~errorを報告-$し~MUST。 ◎ report the error for that script, with the position (line number and column number) where the error occurred, using the WorkerGlobalScope object as the target.
  • 共用~workerに対しては、~errorが依然として`未取扱い$ならば,開発者~consoleに~errorを報告しても~MAY。 ◎ For shared workers, if the error is still not handled afterwards, the error may be reported to a developer console.
  • 専用~workerに対しては、~errorが依然として`未取扱い$ならば,次を走らす`~taskを~queueし$~MUST: ◎ For dedicated workers, if the error is still not handled afterwards, the user agent must queue a task to run these steps:

    1. ~workerに結付けられている `Worker$I ~objに向けて,次のように初期化された`~eventを発火する$ ⇒# `ErrorEvent$I ~interfaceを利用する, 名前 `error$et, `cancelable$m 属性 ~SET ~T, `error$m 属性 ~SET ~NULL, [ `message$m, `filename$m, `lineno$m, `colno$m ]属性 ~SET それぞれに適切な値 ◎ Let notHandled be the result of firing an event named error at Worker object associated with the worker, using ErrorEvent, with the cancelable attribute initialized to true, the message, filename, lineno, and colno attributes initialized appropriately, and the error attribute initialized to null.
    2. ~IF[ 前~段の結果 ~EQ ~T ] ⇒ `Worker$I ~objが属する大域~scopeの中で,~catchされなかった稼働時の~script~errorが生じたかのように、動作する — したがって、一段上層においても,稼働時の~script~errorの報告~処理-が繰返されることになる。 ◎ If notHandled is true, then the user agent must act as if the uncaught runtime script error had occurred in the global scope that the Worker object is in, thus repeating the entire runtime script error reporting process one level up.

[ ~workerの `Worker$I ~objに接続している暗黙的な~port ]の`連絡-$が~~解かれていた場合(すなわち,親の~workerが終了されていた場合)、~UAは[[ `Worker$I ~objは `error$et ~event~handlerを持っていなかった ], かつ[ ~workerの `onerror$m 属性は ~NULL であった ]]かのように,動作し~MUST。 他の場合、上述のように動作し~MUST。 ◎ If the implicit port connecting the worker to its Worker object has been disentangled (i.e. if the parent worker has been terminated), then the user agent must act as if the Worker object had no error event handler and as if that worker's onerror attribute was null, but must otherwise act as described above.

注記: したがって,~error報告-は、専用~workerの連鎖を伝播して — この連鎖に属する,いずれかの~workerが終了され, ~garbage収集されていたとしても — 元の`文書$まで伝播される。 ◎ Thus, error reports propagate up to the chain of dedicated workers up to the original Document, even if some of the workers along this chain have been terminated and garbage collected.

上で言及した~taskの`~task源$は、`~DOM操作~task源$とする。 ◎ The task source for the task mentioned above is the DOM manipulation task source.

10.2.6. ~workerの作成-法

10.2.6.1. `AbstractWorker^I abstract ~interface

[NoInterfaceObject, Exposed=(Window,Worker)]
interface `AbstractWorker@I {
  attribute `EventHandler$I `onerror$mW;
};

`AbstractWorker$I ~interfaceを実装する~objにおいては、次の`~event~handler$(および,それらに対応する`~event~handler ~event型$)が`~event~handler~IDL属性$として~supportされ~MUST: ◎ 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設定群

~UAは, `~workerの環境~設定群~objを設定しておく@ ときは、所与の ( `~JS実行~文脈$ %実行~文脈, `環境~設定群~obj$ %外側~設定群 ) に対し,次の手続きを走らせ~MUST: ◎ When the user agent is required to set up a worker environment settings object, given a JavaScript execution context execution context and environment settings object outside settings, it must run the following steps:

  1. `継承 担当の閲覧文脈^V ~LET %外側~設定群 の`担当の閲覧文脈$enV ◎ Let inherited responsible browsing context be outside settings's responsible browsing context.
  2. `継承 生成元^V ~LET %外側~設定群 の`生成元$enV ◎ Let inherited origin be outside settings's origin.
  3. %~worker~eventloop ~LET 新たに作成された`~eventloop$ ◎ Let worker event loop be a newly created event loop.
  4. %realm ~LET %実行~文脈 の Realm 成分の値 ◎ Let realm be the value of execution context's Realm component.
  5. %~worker大域~scope ~LET %realm の`大域~obj$1 ◎ Let worker global scope be realm's global object.
  6. %設定群~obj ~LET 以下に定義される一連の~algoを備える,新たな`環境~設定群~obj$ : ◎ Let settings object be a new environment settings object whose algorithms are defined as follows:

    `~realm実行~環境$ ◎ The realm execution context
    ~RET %実行~文脈 ◎ Return execution context.
    `~module~map$enV ◎ The module map
    ~RET %~worker大域~scope の`~module~map$wG ◎ Return worker global scope's module map.
    `担当の閲覧文脈$enV ◎ The responsible browsing context
    ~RET `継承 担当の閲覧文脈^V ◎ Return inherited responsible browsing context.
    `担当の~eventloop$enV ◎ The responsible event loop
    ~RET %~worker~eventloop ◎ Return worker event loop.
    `担当の文書$enV ◎ The responsible document
    適用外(`担当の~eventloop$enVは `閲覧文脈$の`~eventloop$xではないので) ◎ Not applicable (the responsible event loop is not a browsing context event loop).
    `~API~URL文字~符号化方式$enV ◎ The API URL character encoding
    ~RET `UTF-8$ ◎ Return UTF-8.
    `~API基底~URL$enV ◎ The API base URL
    ~RET %~worker大域~scope の`~url$wG ◎ Return worker global scope's url.
    `生成元$enV ◎ The origin
    ~RET [ %~worker大域~scope の`~url$wGの`~scheme$url ~EQ `data^l ならば `不透明な生成元$ / ~ELSE_ `継承 生成元^V ] ◎ Return a unique opaque origin if worker global scope's url's scheme is "data", and inherited origin otherwise.
    `~HTTPS状態$enV ◎ The HTTPS state
    ~RET %~worker大域~scope の`~HTTPS状態$wG ◎ Return worker global scope's HTTPS state.
    `~referrer施策$enV ◎ The referrer policy
    ~RET %~worker大域~scope の`~referrer施策$wG ◎ Return worker global scope's referrer policy.
  7. %設定群~obj の ⇒# `~id$enV ~SET 新たな一意かつ不透明な文字列, `作成時の~URL$enV ~SET %~worker大域~scope の`~URL$, `~target閲覧文脈$enV ~SET ~NULL, `作動中の~sw$enV ~SET ~NULL ◎ Set settings object's id to a new unique opaque string, settings object's creation URL to worker global scope's url, settings object's target browsing context to null, and settings object's active service worker to null.
  8. %realm の `HostDefined^sl ~field ~SET %設定群~obj ◎ Set realm's [[HostDefined]] field to settings object.
  9. ~RET %設定群~obj ◎ Return settings object.

10.2.6.3. 専用~workerと `Worker^I ~interface

[Constructor(USVString %scriptURL, optional `WorkerOptions$I %options), Exposed=(Window,Worker)]
interface `Worker@I : `EventTarget$I {
  void `terminate$mW();

  void `postMessage$mW(any %message, optional sequence<`object$> %transfer = []);
  attribute `EventHandler$I `onmessage$mW;
  attribute `EventHandler$I `onmessageerror$mW;
};

dictionary `WorkerOptions@I {
  `WorkerType$I type = "classic";
  `RequestCredentials$I credentials = "omit"; // †
  DOMString name = "";
};

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

`Worker$I implements `AbstractWorker$I;

† `credentials^m (資格証)は、 `type^m (`種別$wG) ~EQ `module^l の場合に限り,利用される。 ◎ credentials is only used if type is "module"

%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 be used to\

  • `name^m ~memberを介して この大域~環境の`名前$wGを定義できる — これは主に、~debug目的にある。 ◎ define the name of that global environment via the name option, primarily for debugging purposes.\
  • `type^m ~memberに `module^l を指定すれば、この新たな大域~環境が~JS~moduleを~supportすることを確保できる — その場合、 `credentials^m ~memberを通して, %scriptURL がどう~fetchされるかも指定できる。 ◎ It can also ensure this new global environment supports JavaScript modules (specify type: "module"), and if that is specified, can also be used to specify how scriptURL is fetched through the credentials option.
%worker . `terminate()$mW
%worker に結付けられている大域~環境を中止する。 ◎ Aborts worker's associated global environment.
%worker . `postMessage(message [, transfer ])$mW
%message を~cloneして %worker の大域~環境へ伝送する。 %transfer には,一連の~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.
`terminate()@mW
被呼出時には、此れが結付けられている~worker上で`~workerを終了させ$~MUST。 ◎ The terminate() method, when invoked, must cause the terminate a worker algorithm to be run on the worker with which the object is associated.

各 `Worker$I ~obj %worker は、 `MessagePort$I ~objである `暗黙的な~port@1 が結付けられているかのように,動作する。 この~portは: ◎ Worker objects act as if they had an implicit MessagePort associated with them. This port is\

  • %worker の作成-時に設定-済みの~channelの一部をなすが,公開されることはない。 ◎ part of a channel that is set up when the worker is created, but it is not exposed.\
  • 決して %worker より先に~garbage収集されてはならない。 ◎ This object must never be garbage collected before the Worker object.
  • この~portから受信されるすべての~messageは、即時に %worker に渡され~MUST。 ◎ All messages received by that port must immediately be retargeted at the Worker object.
`postMessage(message, transfer)@mW
被呼出時には、[ 即時に、此れの`暗黙的な~port$1上の`同じ名前の~method$を,同じ引数で呼出して同じ値を返した ]かのように,動作し~MUST。 ◎ The postMessage() method on Worker objects must act as if, when invoked, it immediately invoked the method of the same name on the 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]
});

`Worker$I ~interfaceを実装する~objにおいては、次の`~event~handler$(および,それらに対応する`~event~handler ~event型$)が`~event~handler~IDL属性$として~supportされ~MUST: ◎ 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 Worker interface:

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

`Worker(scriptURL, options)@m 構築子の被呼出時には、次の手続きを走らせ~MUST: ◎ When the Worker(scriptURL, options) constructor is invoked, the user agent must run the following steps:

  1. ~UAの任意選択で ⇒ ~IF[ この~~要請は施策決定に違反している(例えば~pageに対し,専用~workerの開始-を許容しないように~UAが環境設定されているときなど) ] ⇒ ~THROW `SecurityError^E ◎ The user agent may throw a "SecurityError" DOMException and return if the request violates a policy decision (e.g. if the user agent is configured to not allow the page to start dedicated workers).
  2. %外側~設定群 ~LET `現在の設定群~obj$ ◎ Let outside settings be the current settings object.
  3. %~worker~URL ~LET %scriptURL を %外側~設定群 に`相対的に構文解析-$した`結果の~URL~record$ ◎ Parse the scriptURL argument relative to outside settings.
  4. ~IF[ %~worker~URL ~EQ ~error ] ⇒ ~THROW `SyntaxError^E ◎ If this fails, throw a "SyntaxError" DOMException. ◎ Let worker URL be the resulting URL record.

    注記: `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. %~worker ~LET 新たな `Worker$I ~obj ◎ Let worker be a new Worker object.
  6. %外側~port ~LET `~MessagePort~objを作成する$( %外側~設定群 ) ◎ Create a new MessagePort object whose owner is outside settings. Let this be the outside port.
  7. %~worker の`暗黙的な~port$1 ~SET %外側~port ◎ Associate the outside port with worker.
  8. ~RET %~worker — ただし、以下の手続きは`並列的$に走らす。 ◎ Return worker, and run the following step in parallel.
  9. `~workerを走らす$( %~worker, %~worker~URL, %外側~設定群, %外側~port, %options ) ◎ Run a worker given worker, worker URL, outside settings, outside port, and options.

10.2.6.4. 共用~workerと `SharedWorker^I ~interface

[Constructor(USVString %scriptURL, optional (DOMString or `WorkerOptions$I) %options),
Exposed=(Window,Worker)]
interface `SharedWorker@I : `EventTarget$I {
  readonly attribute `MessagePort$I `port$mW;
};
`SharedWorker$I implements `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 can be used to\

  • `name^m ~memberを介して この大域~環境の`名前$wGを定義できる。 ◎ define the name of that global environment via the name option.\
  • `type^m ~memberに `module^l を指定すれば、この新たな大域~環境が~JS~moduleを~supportすることを確保できる — その場合、 `credentials^m ~memberを通して, %scriptURL がどう~fetchされるかも指定できる。 ◎ It can also ensure this new global environment supports JavaScript modules (specify type: "module"), and if that is specified, can also be used to specify how scriptURL is fetched through the credentials option.
%sharedWorker . `port$mW
%sharedWorker の `MessagePort$I ~objを返す。 それを利用して大域~環境と通信できる。 ◎ Returns sharedWorker's MessagePort object which can be used to communicate with the global environment.
`port@mW
取得子は、此れの構築子により あてがわれた値( %外側~port )を返さ~MUST。 この値は、共用~workerと通信するための `MessagePort$I を表現する。 ◎ The port attribute must return the value it was assigned by the object's constructor. It represents the MessagePort for communicating with the shared worker.

~UAには `共用~worker~manager@ が結付けられる — それは、`新たな並列~queueを開始-$した結果とする。 ◎ A user agent has an associated shared worker manager which is the result of starting a new parallel queue.

注記: 単純にするため、各~UAに結付けられる`共用~worker~manager$は 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(scriptURL, options)@m 構築子の被呼出時には、次を走らす: ◎ When the SharedWorker(scriptURL, options) constructor is invoked:

  1. ~UAの任意選択で ⇒ ~IF[ この~~要請は施策決定に違反している(例えばその~pageに対し,共用~workerの開始-を許容しないように~UAが環境設定されているときなど) ] ⇒ ~THROW `SecurityError^E ◎ Optionally, throw a "SecurityError" DOMException and return if the request violates a policy decision (e.g. if the user agent is configured to not allow the page to start shared workers).
  2. ~IF[ %options は `DOMString^I である ] ⇒ %options ~SET 次のようにされた新たな `WorkerOptions^I 辞書 ⇒# `name^m ~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 outside settings be the current settings object.
  4. %~URL~record ~LET %scriptURL を, %外側~設定群 に`相対的に構文解析-$した`結果の~URL~record$ ◎ Parse scriptURL relative to outside settings.
  5. ~IF[ %~URL~record ~EQ ~error ] ⇒ ~THROW `SyntaxError^E ◎ If this fails, throw a "SyntaxError" DOMException.
  6. %~URL~record ~LET `結果の~URL~record$ ◎ Otherwise, let urlRecord be the resulting URL record.

    注記: `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.

  7. %~worker ~LET 新たな `SharedWorker$I ~obj ◎ Let worker be a new SharedWorker object.
  8. %外側~port ~LET `~MessagePort~objを作成する$( %外側~設定群 ) ◎ Create a new MessagePort object whose owner is outside settings. Let this be the outside port.
  9. %~worker の `port$mW 属性 ~SET %外側~port ◎ Assign outside port to the port attribute of worker.
  10. `~call元は保安的~文脈?^V ~LET `環境~設定群~objは保安的~文脈を与えるか?$( %外側~設定群 ) ◎ Let callerIsSecureContext be the result of executing Is environment settings object a secure context? on outside settings.
  11. `共用~worker~manager$に,次に与える`手続きを~enqueueする$: ◎ Enqueue the following steps to the shared worker manager:

    1. ~IF[ 次の両者とも満たす `SharedWorkerGlobalScope$I ~obj %O は存在する ]… ◎ Let worker global scope be null.

      • %O は次をすべてを満たす:

        • %O の `~closing~flag$i ~EQ ~OFF
        • ( %O の`構築子~生成元$wG, %外側~設定群 の`生成元$enV ) は,`同一生成元$である
        • ( %O の`構築子~url$wG, %~URL~record ) は,`同等$urlである
        • %O の`名前$wG ~EQ %options の `name^m ~member値
        ◎ If there exists a SharedWorkerGlobalScope object whose closing flag is false, constructor origin is same origin with outside settings's origin, constructor url equals urlRecord, and name equals the value of options's name member, then set worker global scope to that SharedWorkerGlobalScope object.

        注記: `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.

      • ~UAは、次を許容しないように環境設定されてはいない ⇒ %O が表現する~workerと[[ `設定群~obj$ ~EQ %外側~設定群 ]なる`~script$たち ]との間の通信 ◎ If worker global scope is not null, but the user agent has been configured to disallow communication between the worker represented by the worker global scope and the scripts whose settings object is outside settings, then set worker global scope 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 browsing context from all other pages, and scripts in that development mode could be blocked from connecting to shared workers running in the normal browser mode.

      …ならば: ◎ If worker global scope is not null, then run these subsubsteps:

      1. %~worker大域~scope ~LET 前述に該当した %O 【該当するものは複数あり得るかも?】 ◎ ↑
      2. %設定群~obj ~LET %~worker大域~scope に`関連する設定群~obj$ ◎ Let settings object be the relevant settings object for worker global scope.
      3. `~workerは保安的~文脈?^V ~LET `環境~設定群~objは保安的~文脈を与えるか?$( %設定群~obj ) ◎ Let workerIsSecureContext be the result of executing Is environment settings object a secure context? on settings object.
      4. ~IF[ `~workerは保安的~文脈?^V ~NEQ `~call元は保安的~文脈?^V ]:

        1. 次を走らす`~taskを~queueする$ ⇒ %~worker に向けて,名前 `error$et の`~eventを発火する$
        2. ~RET
        `SECURE-CONTEXTS$r ◎ If workerIsSecureContext is not callerIsSecureContext, then queue a task to fire an event named error at worker and abort these subsubsteps. [SECURE-CONTEXTS]
      5. %~worker を %~worker大域~scope に結付ける ◎ Associate worker with worker global scope.
      6. %内側~port ~LET `~MessagePort~objを作成する$( %設定群~obj ) ◎ Create a new MessagePort object whose owner is settings object. Let this be the inside port.
      7. `~portを連絡する$( %外側~port, %内側~port ) ◎ Entangle outside port and inside port.
      8. `~DOM操作~task源$から,次を走らす`~taskを~queueする$ ⇒ %~worker大域~scope に向けて,次のように初期化された`~eventを発火する$ ⇒# `MessageEvent$I ~interfaceを利用する, 名前 `connect$et, `data$m 属性 ~SET 空~文字列, `ports$m 属性 ~SET %内側~port のみを含む新たな`凍結~配列$, `source$m 属性 ~SET %内側~port ◎ Queue a task, using the DOM manipulation task source, 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 only inside port, and the source attribute initialized to inside port.

      9. %~worker大域~scope の`所有者~集合$wGに[ %外側~設定群 から与えられる,`関連する所有者として追加するもの$ ]を`付加する$set ◎ Append the relevant owner to add given outside settings to worker global scope's owner set.
      10. ~IF[[ %外側~設定群 の`大域~obj$enV %G ]は `WorkerGlobalScope$I ~objである ] ⇒ %G の`~worker集合$wGに %~worker大域~scope を`付加する$set ◎ If outside settings's global object is a WorkerGlobalScope object, then append worker global scope to outside settings's global object's worker set.
    2. ~ELSE ⇒ `並列的$に,`~workerを走らす$( %~worker, %~URL~record, %外側~設定群, %外側~port, %options ) ◎ Otherwise, in parallel, run a worker given worker, urlRecord, outside settings, outside port, and options.
  12. ~RET %~worker ◎ Return worker.

10.3. ~workerから可用な~API

10.3.1. ~script/~libraryの取込み

`WorkerGlobalScope$I ~objの `importScripts(urls)@m ~methodの被呼出時には、次を走らせ~MUST ⇒ `~scriptを~worker大域~scopeの中に取込む$( 此れ, %urls ) ◎ When a script invokes the importScripts(urls) method on a WorkerGlobalScope object, the user agent must import scripts into worker global scope given this WorkerGlobalScope object and urls.

`~scriptを~worker大域~scopeの中に取込む@ ときは、所与の ⇒# `WorkerGlobalScope$I ~obj %~worker大域~scope, `sequence<DOMString>^I 型~値 %urls, ◎終 に対し,次の手続きを走らせ~MUST — この手続きには、`~fetchを遂行する$ ~custom~hookも供されて~MAY (供された場合、`~workerが取込んだ~classic~scriptを~fetchする$ときに利用される): ◎ To import scripts into worker global scope, given a WorkerGlobalScope object worker global scope and a sequence<DOMString> urls, run these steps. The algorithm may optionally be customized by supplying custom perform the fetch hooks, which if provided will be used when invoking fetch a classic worker-imported script.

  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[ %urls は空である ] ⇒ ~RET ◎ If urls is empty, return.
  4. %~url~list ~LET 空~list ◎ ↓
  5. %urls 内の ~EACH ( %~url ) に対し:

    1. %~url ~SET %~url を %設定群~obj に`相対的に構文解析-$した`結果の~URL~record$
    2. ~IF[ %~url ~EQ ~error ] ⇒ ~THROW `SyntaxError^E
    3. %~url~list に %~url を付加する
    ◎ Parse each value in urls relative to settings object. If any fail, throw a "SyntaxError" DOMException.
  6. %~url~list 内の ~EACH ( %url ) に対し: ◎ For each url in the resulting URL records, run these substeps:

    1. %~script ~LET `~workerが取込んだ~classic~scriptを~fetchする$( %url, %設定群~obj ) — `~fetchを遂行する$ ~custom手続きが提供されていれば それも渡す (例外~投出あり) ◎ Fetch a classic worker-imported script given url and settings object, passing along any custom perform the fetch steps provided. If this succeeds, let script be the result. Otherwise, rethrow the exception.
    2. `~classic~scriptを走らす$( %~script, %~errorは再投出する ~SET ~T ) ◎ Run the classic script script, with the rethrow errors argument set to true.

      注記: ~scriptは、次のいずれかが生じるまで走らすことになる:

      • 普通に返った
      • 構文解析-に失敗した
      • 投出された例外を~catchしなかった
      • `~workerが終了され$たため,`尚早に中止され$た
      ◎ 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 仕様 `SW$r は、`~fetchを遂行する$ ~hookに自前の~optionを与えて この~algoを走らす仕様の例である。 ◎ Service Workers is an example of a specification that runs this algorithm with its own options for the perform the fetch hook. [SW]

10.3.2. `WorkerNavigator^I ~interface

`WorkerGlobalScope$I ~interfaceの `navigator@m 属性は、~UA(~client)の識別と状態を表現する, `WorkerNavigator$I ~interfaceの~instanceを返さ~MUST。 ◎ 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 implements `NavigatorID$I;
`WorkerNavigator$I implements `NavigatorLanguage$I;
`WorkerNavigator$I implements `NavigatorOnLine$I;
`WorkerNavigator$I implements `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;
};

各 `WorkerLocation$I ~objには、[ `WorkerGlobalScope$I ~objである `~worker大域~scope@ ]が結付けられる。 ◎ A WorkerLocation object has an associated WorkerGlobalScope object (a WorkerGlobalScope object).

この節を通して、 `url@V は,当の `WorkerLocation$I ~objの`~worker大域~scope$の`~url$wGを表すとする。 ◎ ↓

`href@m
取得子は、次の結果を返さ~MUST ⇒ `~URLを直列化する$( `url$V ) ◎ The href attribute's getter must return the associated WorkerGlobalScope object's url, serialized.
`origin@m
取得子は、次の結果を返さ~MUST ⇒ `生成元を直列化する$( `url$V の`生成元$url ) ◎ The origin attribute's getter must return the serialization of the associated WorkerGlobalScope object's url's origin.
`protocol@m
取得子は、次を順に連結した結果を返さ~MUST ⇒# `url$V の`~scheme$url, `:^l ◎ The protocol attribute's getter must return the associated WorkerGlobalScope object's url's scheme, followed by ":".
`host@m

取得子は、次を走らせ~MUST: ◎ The host attribute's getter must run these steps:

  1. %host ~LET `url$V の`~host$url ◎ ↓
  2. ~IF[ %host ~EQ ~NULL ] ⇒ ~RET 空~文字列 ◎ Let url be the associated WorkerGlobalScope object's url. ◎ If url's host is null, return the empty string.
  3. %host ~LET `~hostを直列化する$( %host ) ◎ ↓
  4. %port ~LET `url$V の`~port$url ◎ ↓
  5. ~IF[ %port ~EQ ~NULL ] ⇒ ~RET %host ◎ If url's port is null, return url's host, serialized.
  6. ~RET 次を順に連結した結果 ⇒# %host, `:^l, `整数を直列化する$( %port ) ◎ Return url's host, serialized, followed by ":" and url's port, serialized.

`hostname@m

取得子は、次を走らせ~MUST: ◎ The hostname attribute's getter must run these steps:

  1. %host ~LET `url$V の`~host$url ◎ Let host be the associated 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

取得子は、次を走らせ~MUST: ◎ The port attribute's getter must run these steps:

  1. %port ~LET `url$V の`~port$url ◎ Let port be the associated 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

取得子は、次を走らせ~MUST: ◎ The pathname attribute's getter must run these steps:

  1. ~IF[ `url$V の`~cannot-be-a-base-URL~flag$url ~EQ ~ON ] ⇒ ~RET `url$V の`~path$url内の最初の文字列 ◎ Let url be the associated WorkerGlobalScope object's url. ◎ If url's cannot-be-a-base-URL flag is set, return the first string in url's path.
  2. ~RET 次を順に連結した結果 ⇒# `/^l, `url$V の`~path$url内の各~文字列(空~文字列も含め)を, `/^l で区切って順に連結した結果 ◎ Return "/", followed by the strings in url's path (including empty strings), separated from each other by "/".
`search@m

取得子は、次を走らせ~MUST: ◎ The search attribute's getter must run these steps:

  1. %query ~LET `url$V の`~query$url ◎ Let query be the associated 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

取得子は、次を走らせ~MUST: ◎ The hash attribute's getter must run these steps:

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