Web Workers

Draft Recommendation — 1 June 2010勧告案の非公式和訳(原文出版日) 1 June 2010

You can take part in this work. Join the working group's discussion list.みなさんにも作業にご参加いただけます。 作業部会の議論用メイリング・リストに参加してください。

Web designers! We have a FAQ, a forum, and a help mailing list for you!Web デザイナーのみなさん! みなさんのための FAQ掲示板ヘルプ用メイリング・リストがあります!

この文書は、 WHATWG 仕様書の日本語訳です。 正式な仕様書は英語版だけであり、この日本語訳はあくまで参考としてご利用ください。

This document is a non-normative Japanese translation of the WHATWG specification. Only the original English version is normative and this Japanese translation is non‐normative.

日本語訳は段落をダブルクリックすると編集できます。アカウントを作成して spec-ja グループに参加してください。編集結果はおよそ3時間おきに反映されます。また、原文の変更には毎日自動的に追随しています。 (詳細)

You can edit Japanese text by double-clicking the paragraph you'd like to edit. Create an account and join the spec-ja group. Any additions of and modifications to Japanese text will be applied to the document within about three hours. Any changes to the original English specification will automatically be incorporated to the document every day. (Details)

他の翻訳のリストもご覧ください。

See also the list of translations.

This version:原文のこの版
http://whatwg.org/ww
Version history:原文の改版履歴:
Twitter messages (non-editorial changes only): http://twitter.com/WHATWGTwitter メッセージ (編集上の変更以外): http://twitter.com/WHATWG
Commit-Watchers mailing list: http://lists.whatwg.org/listinfo.cgi/commit-watchers-whatwg.orgCommit-Watchers メイリング・リスト: http://lists.whatwg.org/listinfo.cgi/commit-watchers-whatwg.org
Interactive Web interface: http://html5.org/tools/web-workers-tracker対話的 Web 界面: http://html5.org/tools/web-workers-tracker
Subversion interface: http://svn.whatwg.org/webworkers/Subversion 界面: http://svn.whatwg.org/webworkers/
Issues:問題:
To send feedback: whatwg@whatwg.orgフィードバックの送信先: whatwg@whatwg.org
To view and vote on feedback: http://www.whatwg.org/issues/フィードバックの閲覧・投票: http://www.whatwg.org/issues/
Editor:編集者:
Ian Hickson, Google, ian@hixie.ch

Abstract概要

This specification defines an API that allows Web application authors to spawn background workers running scripts in parallel to their main page. This allows for thread-like operation with message-passing as the coordination mechanism.この仕様書は、 Web アプリケーションで、主たる頁とは並列に、 背景労働者スクリプトを走らせるための API を定義します。 これにより、メッセージ・パッシングによるスレッド的操作を協調機構として利用できるようになります。

Status of this documentこの文書の状態

This is a work in progress! This document is changing on a daily if not hourly basis in response to comments and as a general part of its development process. Comments are very welcome, please send them to whatwg@whatwg.org. Thank you.この文書は作業中です! この文書は、コメントへの対応や通常の開発の過程として、 毎時毎分とは言い過ぎですが毎日のペースで変更されています。 コメントは非常に歓迎していますので、 whatwg@whatwg.org へお送りください。よろしくお願いします。

The current focus is in developing a first draft proposal.現在の焦点は、第1案の開発です。

Implementors should be aware that this specification is not stable. Implementors who are not taking part in the discussions are likely to find the specification changing out from under them in incompatible ways. Vendors interested in implementing this specification before it eventually reaches the call for implementations should join the WHATWG mailing list and take part in the discussions.実装者は、この仕様書が安定していないことに注意するべきです。 実装者は議論に参加しておかないと、 仕様がその実装とは非互換に変更されてしまうかもしれません。 この仕様書がいずれ実装呼び掛けの段階に達するのよりも前にこの仕様を実装したい販売者は、 WHATWG メイリング・リストに参加し、 議論に加わるべきです。

This specification is also being produced by the W3C Web Apps WG. The two specifications are identical from the table of contents onwards.

Table of contents目次

  1. 1 Introduction

    1. 1.1 Scope

    2. 1.2 Tutorial

      1. 1.2.1 A background number-crunching worker

      2. 1.2.2 A worker for updating a client-side database

      3. 1.2.3 Worker used for background I/O

      4. 1.2.4 Shared workers introduction

      5. 1.2.5 Shared state using a shared worker

      6. 1.2.6 Delegation

      7. 1.2.7 Providing libraries

  2. 2 Conformance requirements

    1. 2.1 Dependencies

  3. 3 Terminology

  4. 4 Infrastructure

    1. 4.1 The global scope

      1. 4.1.1 The WorkerGlobalScope abstract interface

      2. 4.1.2 Dedicated workers and the DedicatedWorkerGlobalScope interface

      3. 4.1.3 Shared workers and the SharedWorkerGlobalScope inteface

    2. 4.2 Origins of workers

    3. 4.3 The event loop

    4. 4.4 The worker's lifetime

    5. 4.5 Processing model

    6. 4.6 Runtime script errors

    7. 4.7 Creating workers

      1. 4.7.1 The AbstractWorker abstract interface

      2. 4.7.2 Dedicated workers and the Worker interface

      3. 4.7.3 Shared workers and the SharedWorker interface

  5. 5 APIs available to workers

    1. 5.1 Importing scripts and libraries

    2. 5.2 The WorkerNavigator object

    3. 5.3 APIs defined in other specifications

    4. 5.4 Interface objects and constructors

    5. 5.5 Worker locations

  6. References

  7. Acknowledgements


1 Introduction1 はじめに

1.1 Scope1.1 適用範囲

This section is non-normative.

This specification defines an API for running scripts in the background independently of any user interface scripts.

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.

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.

Generally, workers are expected to be long-lived, have a high start-up performance cost, and a high per-instance memory cost.

1.2 Tutorial1.2 解説

This section is non-normative.

There are a variety of uses that workers can be put to. The following subsections show various examples of this use.労働者は色々なことに使えます。次の各節では、色々な使い方の例を示します。

1.2.1 A background number-crunching worker1.2.1 数値処理背景労働者

This section is non-normative.

The simplest use of workers is for performing a computationally expensive task without interrupting the user interface.労働者の一番単純な用法は、計算的に高価な仕事を利用者界面を中断させずに実行するというものです。

In this example, the main document spawns a worker to (naïvely) compute prime numbers, and progressively displays the most recently found prime number.この例では、主たる文書が労働者を作って素数を (素朴な方法で) 計算させ、 新しく見つかった素数を順番に表示してゆきます。

The main page is as follows:主たる頁は次の通りです。

<!DOCTYPE HTML>
<html>
 <head>
  <title>Worker example: One-core computation</title>
 </head>
 <body>
  <p>The highest prime number discovered so far is: <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>

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.

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);
}

The bulk of this code is simply an unoptimized search for a prime number. To send a message back to the page, the postMessage() method is used to post a message when a prime is found.

View this example online.この例をオンラインで表示する

1.2.2 A worker for updating a client-side database1.2.2 クライアント側データベースの更新のための労働者

This section is non-normative.

In this example, the main document spawns a worker whose only task is to listen for notifications from the server, and, when appropriate, either add or remove data from the client-side database.

Since no communication occurs between the worker and the main page, the main page can start the worker by just doing:労働者と主たる頁の間に通信は発生しませんので、 主たる頁は単に次のようにするだけで労働者を開始できます。

<script>
 new Worker('worker.js');
</script>

The worker itself is as follows:労働者自体は次の通りです。

var server = new WebSocket('ws://whatwg.org/database');
var database = openDatabase('demobase', '1.0', 'Demo Database', 10240);
server.onmessage = function (event) {
  // data is in the format "command key value"
  var data = event.data.split(' ');
  switch (data[0]) {
    case '+':
     database.transaction(function(tx) {
       tx.executeSql('INSERT INTO pairs (key, value) VALUES (?, ?)', data[1], data[2]);
     });
    case '-':
     database.transaction(function(tx) {
       tx.executeSql('DELETE FROM pairs WHERE key=? AND value=?', data[1], data[2]);
     });
  }
};

This connects to the server using the WebSocket mechanism and opens the local database (which, we presume, has been created earlier). The worker then just listens for messages from the server and acts on them as appropriate, forever (or until the main page is closed).

View this example online. (This example will not actually function, since the server does not actually exist and the database is not created by this sample code.)

1.2.3 Worker used for background I/O

This section is non-normative.

In this example, the main document uses two workers, one for fetching stock updates for at regular intervals, and one for fetching performing search queries that the user requests.この例では、主たる文書は2つの労働者を使います。 1つは一定間隔で株価の更新を取得するためのもので、もう1つは利用者の要求した検索の照会を行う取得のためのものです。

The main page is as follows:主たる頁は次の通りです。

<!DOCTYPE HTML>
<html>
 <head>
  <title>Worker example: Stock ticker</title>
  <script>
   // TICKER
   var symbol = 'GOOG'; // default symbol to watch
   var ticker = new Worker('ticker.js');

   // SEARCHER
   var searcher = new Worker('searcher.js');
   function search(query) {
     searcher.postMessage(query);
   }

   // SYMBOL SELECTION UI
   function select(newSymbol) {
     symbol = newSymbol;
     ticker.postMessage(symbol);
   }
  </script>
 </head>
 <body onload="search('')">
  <p><output id="symbol"></output> <output id="value"></output></p>
  <script>
   ticker.onmessage = function (event) {
     var data = event.data.split(' ');
     document.getElementById('symbol').textContent = data[0];
     document.getElementById('value').textContent = data[1];
   };
   ticker.postMessage(symbol);
  </script>
  <p><label>Search: <input type="text" autofocus oninput="search(this.value)"></label></p>
  <ul id="results"></ul>
  <script>
   searcher.onmessage = function (event) {
     var data = event.data.split(' ');
     var results = document.getElementById('results');
     while (results.hasChildNodes()) // clear previous results
       results.removeChild(results.firstChild);
     for (var i = 0; i < data.length; i += 1) {
       // add a list item with a button for each result
       var li = document.createElement('li');
       var button = document.createElement('button');
       button.value = data[i];
       button.type = 'button';
       button.onclick = function () { select(this.value); };
       button.textContent = data[i];
       li.appendChild(button);
       results.appendChild(li);
     }
   };
  </script>
  <p>(The data in this example is not real. Try searching for "Google" or "Apple".)</p>
 </body>
</html>

The two workers use a common library for performing the actual network calls. This library is as follows:両労働者は実際のネットワークの呼び出しを行う共通のライブラリーを使います。 このライブラリーは次の通りです。

function get(url) {
  try {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, false);
    xhr.send();
    return xhr.responseText;
  } catch (e) {
    return ''; // turn all errors into empty results
  }
}

The stock updater worker is as follows:株価更新者の労働者は次の通りです。

importScripts('io.js');
var timer;
var symbol;
function update() {
  postMessage(symbol + ' ' + get('stock.cgi?' + symbol));
  timer = setTimeout(update, 10000);
}
onmessage = function (event) {
  if (timer)
    clearTimeout(timer);
  symbol = event.data;
  update();
};

The search query worker is as follows:検索の照会の労働者は次の通りです。

importScripts('io.js');
onmessage = function (event) {
  postMessage(get('search.cgi?' + event.data));
};

View this example online.この例をオンラインで表示する

1.2.4 Shared workers introduction

This section is non-normative.

This section introduces shared workers using a Hello World example. Shared workers use slightly different APIs, since each worker can have multiple connections.

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.

Here is the HTML page:

<!DOCTYPE HTML>
<title>Shared workers: 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) { // note: not worker.onmessage!
    log.textContent += '\n' + e.data;
  }
</script>

Here is the JavaScript worker:

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

View this example online.この例をオンラインで表示する


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.

Here is the HTML page:

<!DOCTYPE HTML>
<title>Shared workers: 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(); // note: need this when using addEventListener
  worker.port.postMessage('ping');
</script>

Here is the JavaScript worker:

onconnect = function(e) {
  var port = e.ports[0];
  port.postMessage('Hello World!');
  port.onmessage = function(e) {
    port.postMessage('pong'); // not e.ports[0].postMessage!
    // e.target.postMessage('pong'); would work also
  }
}

View this example online.この例をオンラインで表示する


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.

Here is the outer HTML page:

<!DOCTYPE HTML>
<title>Shared workers: 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>

Here is the inner HTML page:

<!DOCTYPE HTML>
<title>Shared workers: 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>

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');
  }
}

View this example online.この例をオンラインで表示する

1.2.5 Shared state using a shared worker

This section is non-normative.

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.

The main page isn't interesting, it merely provides a way to open the viewers:主たる頁は特に何もなく、単に表示器を開くためだけのものです。

<!DOCTYPE HTML>
<html>
 <head>
  <title>Workers example: Multiviewer</title>
  <script>
   function openViewer() {
     window.open('viewer.html');
   }
  </script>
 </head>
 <body>
  <p><button type=button onclick="openViewer()">Open a new
  viewer</button></p>
  <p>Each viewer opens in a new window. You can have as many viewers
  as you like, they all view the same data.</p>
 </body>
</html>

The viewer is more involved:表示器はもっと色々しています。

<!DOCTYPE HTML>
<html>
 <head>
  <title>Workers example: 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);
     // update display to mention our name is name
     document.getElementsByTagName('h1')[0].textContent += ' ' + name;
     // 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(',');
     // 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';
         fillRect(x * 50, y * 50, 50, 50);
       }
     }
   }
   worker.port.addEventListener('message', paintMap, false);

   // PUBLIC CHAT
   function updatePublicChat(event) {
     if (event.data.substr(0, 4) != 'txt ') return;
     var name = event.data.substr(4).split(' ', 1);
     var message = event.data.substr(4 + length(name) + 1);
     // display "<name> message" in public chat
     var dialog = document.getElementById('public');
     var dt = document.createElement('dt');
     dt.textContent = name;
     dialog.appendChild(dt);
     var dd = document.createElement('dd');
     dd.textContent = message;
     dialog.appendChild(dd);
   }
   worker.port.addEventListener('message', updatePublicChat, false);

   // PRIVATE CHAT
   function startPrivateChat(event) {
     if (event.data.substr(0, 4) != 'msg ') return;
     var name = event.data.substr(4).split(' ', 1);
     var port = event.ports[0];
     // 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 dialog = document.createElement('dialog');
     var addMessage = function(name, message) {
       var dt = document.createElement('dt');
       dt.textContent = name;
       dialog.appendChild(dt);
       var dd = document.createElement('dd');
       dd.textContent = message;
       dialog.appendChild(dd);
     };
     port.onmessage = function (event) {
       addMessage(name, event.data);
     };
     li.appendChild(dialog);
     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);
   }
   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>
  <dialog id="public"></dialog>
  <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>

There are several key things worth noting about the way the viewer is written.表示器の書き方についていくつか注意したい重要な点があります。

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.複数の聴取器。この符号では、メッセージ処理関数を1つ用意する代わりに、 複数の事象聴取器を付与し、それぞれが、それがメッセージに関連するかどうかを見るためにさらりと検査を行っています。 この例では大きな違いにはなりませんが、複数の著者が労働者と通信するために1つのポートを使って協調したい場合には、 独立した符号にできるので変更がある度に1つの事象取扱関数をいじらざるを得なくて済みます。

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.

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 sendMapData(callback) {
  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[y][x];
    }
  }
  callback('map ' + data);
}

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

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.postMessage);
      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].port.postMessage);
      break;
    case 'txt ':
      var name = event.target._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._data;
      var party2 = viewers[event.data.substr(4).split(' ', 1)];
      if (party2) {
        var channel = new MessageChannel();
        party1.port.postMessage('msg ' + party2.name, [channel.port1]);
        party2.port.postMessage('msg ' + party1.name, [channel.port2]);
      }
      break;
  }
}

Connecting to multiple pages. The script uses the onconnect event listener to listen for multiple connections.

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.直接通信路。労働者がある閲覧器から他の閲覧器を名指した「msg」メッセージを受信した時は、 両者間の直接の接続を設定し、労働者がすべてのメッセージを仲介せずとも両閲覧器が直接通信できるようにします。

View this example online.この例をオンラインで表示する

1.2.6 Delegation1.2.6 委譲

This section is non-normative.

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.

The main page is as follows, it just reports the result:主たる頁は次の通りで、単に結果を報告するだけです。

<!DOCTYPE HTML>
<html>
 <head>
  <title>Worker example: Multicore computation</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>

The worker itself is as follows:労働者自体は次の通りです。

// settings
var num_workers = 10;
var items_per_worker = 1000000;

// 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!
}

It consists of a loop to start the subworkers, and then a handler that waits for all the subworkers to respond.これは部分労働者を開始するループと、 すべての部分労働者が応答するのを待つ取扱器から成っています。

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();
}

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.部分労働者は2つの事象で2つの数を受信し、指定された数の範囲の計算を行った後、 結果を親に報告します。

View this example online.この例をオンラインで表示する

1.2.7 Providing libraries1.2.7 ライブラリーの提供

This section is non-normative.

Suppose that a cryptography library is made available that provides three tasks:

Generate a public/private key pair公開鍵・秘密鍵の組の生成
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
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
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.

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));
    }
  };
}

// support being used as a shared worker as well as a dedicated worker
if ('onmessage' in this) // dedicated worker
  onmessage = handleMessage;
else // shared 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);
}

Note that the crypto functions here are just stubs and don't do real cryptography.

This library could be used as follows:このライブラリーは次のように使うことができます。

<!DOCTYPE HTML>
<html>
 <head>
  <title>Worker example: Crypto library</title>
  <script>
   var crytoLib = new Worker('libcrypto-v1.js'); // or could use 'libcrypto-v2.js'
   function getKeys() {
     var state = 0;
     cryptoLib.startConversation("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() {
     var port = cryptoLib.startConversation("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() {
     var port = cryptoLib.startConversation("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>

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]);
  };
}

// support being used as a shared worker as well as a dedicated worker
if ('onmessage' in this) // dedicated worker
  onmessage = handleMessage;
else // shared worker
  onconnect = function (e) { e.ports[0].onmessage = handleMessage };

The little subworkers would then be as follows.小部分労働者は次の通りです。

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);
}

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.

View this example online.この例をオンラインで表示する

2 Conformance requirements2 適合性要件

All diagrams, examples, and notes in this specification are non-normative, as are all sections explicitly marked non-normative. Everything else in this specification is normative.この仕様書のすべての図、例示、注意書き、ならびに規定の一部ではないと明記したすべての節は、 規定の一部ではありません。 この仕様書のそれ以外の部分はすべて規定の一部です。

The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the normative parts of this document are to be interpreted as described in RFC2119. For readability, these words do not appear in all uppercase letters in this specification. [RFC2119]この文書の規定の部分にあるキーワード「しなければなりません」、 「してはなりません」、 「必須です」、するべきです」、 「するべきではありません」、 「推奨します」、「して構いません」、 「任意です」は、 RFC 2119 で説明されているように解釈します。 この仕様書の原文では、 可読性の観点から、 これらの語の原語のすべて大文字による表記は行っていません。 [RFC2119]

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.算法の一部として動作の指示の形で (原文では命令形で) 記述された要件 (例えば「先頭の間隔文字をすべて除去します」や「偽を返し、これらの段階を停止します」) は、算法を紹介するに当たって使われたキーワード (しなければなりませんするべきですして構いませんなど) の意味により解釈します。

Some conformance requirements are phrased as requirements on attributes, methods or objects. Such requirements are to be interpreted as requirements on user agents.いくつかの適合性要件は属性やメソッドやオブジェクトの要件として説明されています。 そのような要件は、利用者エージェントに関する要件として解釈します。

Conformance requirements phrased as algorithms or specific steps may be implemented in any manner, so long as the end result is equivalent. (In particular, the algorithms defined in this specification are intended to be easy to follow, and not intended to be performant.)算法や特定の段階として説明されている適合性要件は、 最終的な結果が等価である限り、任意の方法で実装して構いません。 (特に、この仕様書で定義されている算法は追うのを簡単にしており、 高性能であることを目指してはいません。)

The only conformance class defined by this specification is user agents.この仕様書で定義する唯一の適合性の級は利用者エージェントです。

User agents may impose implementation-specific limits on otherwise unconstrained inputs, e.g. to prevent denial of service attacks, to guard against running out of memory, or to work around platform-specific limitations.利用者エージェントは、サービス拒否攻撃を防ぐため、 記憶容量を使い尽くすことを防ぐため、 あるいは環境特有の制限に対応するためなどの目的で、 別段の制約のない入力に対して実装特有の制限を設けて構いません

When support for a feature is disabled (e.g. as an emergency measure to mitigate a security problem, or to aid in development, or for performance reasons), user agents must act as if they had no support for the feature whatsoever, and as if the feature was not mentioned in this specification. For example, if a particular feature is accessed via an attribute in a Web IDL interface, the attribute itself would be omitted from the objects that implement that interface — leaving the attribute on the object but making it return null or throw an exception is insufficient.

2.1 Dependencies2.1 依存性

This specification relies on several other underlying specifications.この仕様書は、他のいくつかの下位の仕様書に依存しています。

HTML

Many fundamental concepts from HTML are used by this specification. [HTML]

WebIDL

The IDL blocks in this specification use the semantics of the WebIDL specification. [WEBIDL]

3 Terminology3 用語

The construction "a Foo object", where Foo is actually an interface, is sometimes used instead of the more accurate "an object implementing the interface Foo".Foo オブジェクト」という構文 (Foo は実際には界面) を時々使いますが、より正確な「界面 Foo を実装しているオブジェクト」の代わりに用いています。

The term DOM is used to refer to the API set made available to scripts in Web applications, and does not necessarily imply the existence of an actual Document object or of any other Node objects as defined in the DOM Core specifications. [DOMCORE]

An IDL attribute is said to be getting when its value is being retrieved (e.g. by author script), and is said to be setting when a new value is assigned to it.

The term "JavaScript" is used to refer to ECMA262, rather than the official term ECMAScript, since the term JavaScript is more widely known. [ECMA262]

4 Infrastructure4 基盤

There are two kinds of workers; dedicated workers, and shared workers. Dedicated workers, once created, and 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.

4.1 The global scope4.1 大域作用域

The global scope is the "inside" of a worker.大域作用域は労働者の「内側」です。

4.1.1 The WorkerGlobalScope abstract interface4.1.1 WorkerGlobalScope 抽象界面

interface WorkerGlobalScope {
  readonly attribute WorkerGlobalScope self;
  readonly attribute WorkerLocation location;

  void close();
           attribute Function onerror;
};
WorkerGlobalScope implements WorkerUtils;
WorkerGlobalScope implements EventTarget;

The self attribute must return the WorkerGlobalScope object itself.

The location attribute must return the WorkerLocation object created for the WorkerGlobalScope object when the worker was created. It represents the absolute URL of the script that was used to initialize the worker, after any redirects.


When a script invokes the close() method on a WorkerGlobalScope object, the user agent must run the following steps (atomically):

  1. Discard any tasks that have been added to the event loop's task queues.

  2. Set the worker's WorkerGlobalScope object's closing flag to true. (This prevents any further tasks from being queued.)

The following are the event handlers (and their corresponding event handler event types) that must be supported, as IDL attributes, by objects implementing the WorkerGlobalScope interface:

Event handler Event handler event type
onerror error

The WorkerGlobalScope interface must not exist if the interface's relevant namespace object is a Window object. [WEBIDL]

4.1.2 Dedicated workers and the DedicatedWorkerGlobalScope interface

[Supplemental, NoInterfaceObject]
interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
  void postMessage(in any message, in optional MessagePortArray ports);
           attribute Function onmessage;
};

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.

All messages received by that port must immediately be retargeted at the DedicatedWorkerGlobalScope object.

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.

The following are the event handlers (and their corresponding event handler event types) that must be supported, as IDL attributes, by objects implementing the DedicatedWorkerGlobalScope interface:

Event handler Event handler event type
onmessage message

For the purposes of the application cache networking model, a dedicated worker is an extension of the cache host from which it was created.

4.1.3 Shared workers and the SharedWorkerGlobalScope inteface

[Supplemental, NoInterfaceObject]
interface SharedWorkerGlobalScope : WorkerGlobalScope {
  readonly attribute DOMString name;
  readonly attribute ApplicationCache applicationCache;
           attribute Function onconnect;
};

Shared workers receive message ports through connect events on their global object for each connection.共有労働者は、各接続について大域オブジェクトの connect 事象を通じてメッセージ・ポートを受信します。

The name attribute must return the value it was assigned when the SharedWorkerGlobalScope object was created by the "run a worker" algorithm. Its value represents the name that can be used to obtain a reference to the worker using the SharedWorker constructor.

The following are the event handlers (and their corresponding event handler event types) that must be supported, as IDL attributes, by objects implementing the SharedWorkerGlobalScope interface:

Event handler Event handler event type
onconnect connect

For the purposes of the application cache networking model, a shared worker is its own cache host. The run a worker algorithm takes care of associating the worker with an application cache.

The applicationCache attribute returns the ApplicationCache object for the worker.

4.2 Origins of workers

Both the origin and effective script origin of scripts running in workers are the origin of the absolute URL given in that the worker's location attribute represents.

4.3 The event loop

Each WorkerGlobalScope object has an event loop distinct from those defined for 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. The processing model of these event loops is defined below in the run a worker algorithm.

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.

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 asynchronous operations are dropped, etc.

4.4 The worker's lifetime

Workers communicate with other workers and with browsing contexts through message channels and their MessagePort objects.労働者は、メッセージ通信路とその MessagePort オブジェクトを通じて、他の労働者や閲覧文脈と通信します。

Each WorkerGlobalScope worker global scope has a list of the worker's ports, 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. This list includes the implicit MessagePort in the case of dedicated workers.

Each WorkerGlobalScope also has a list of the worker's workers. Initially this list is empty; it is populated when the worker creates or obtains further workers.

Finally, each WorkerGlobalScope also has a list of the worker's Documents. Initially this list is empty; it is populated when the worker is created.

Whenever a Document d is added to the worker's Documents, the user agent must, for each worker in the list of the worker's workers whose list of the worker's Documents does not contain d, add d to q's WorkerGlobalScope owner's list of the worker's Documents.

Whenever a Document object is discarded, it must be removed from the list of the worker's Documents of each worker whose list contains that Document.

Given a script's global object o when creating or obtaining a worker, the list of relevant Document objects to add depends on the type of o. If o is a WorkerGlobalScope object (i.e. if we are creating a nested worker), then the relevant Documents are the Documents that are in o's own list of the worker's Documents. Otherwise, o is a Window object, and the relevant Document is just the Document that is the active document of the Window object o.


A worker is said to be a permissible worker if its list of the worker's Documents is not empty.

A worker is said to be a protected worker if it is a permissible worker and 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).

A worker is said to be an active needed worker if any of the Document objects in the worker's Documents are fully active.

A worker is said to be a suspendable worker if it is not an active needed worker but it is a permissible worker.

4.5 Processing model4.5 処理モデル

When a user agent is to run a worker for a script with URL url, a browsing context owner browsing context, a Document owner document, an origin owner origin, and with global scope worker global scope, it must run the following steps:

  1. Create a completely separate and parallel execution environment (i.e. a separate thread or process or equivalent construct), and run the rest of these steps asynchronously in that context.

  2. If worker global scope is actually a SharedWorkerGlobalScope object (i.e. the worker is a shared worker), and there are any relevant application caches that are identified by a manifest URL with the same origin as url and that have url as one of their entries, not excluding entries marked as foreign, then associate the worker global scope with the most appropriate application cache of those that match.

  3. Attempt to fetch the resource identified by url, from the owner origin.

    If the attempt fails, or if the attempt involves any redirects to URIs that do not have the same origin as url (even if the final URI is at the same origin as the original url), then for each Worker or SharedWorker object associated with worker global scope, queue a task to fire a simple event named error at that object. Abort these steps.

    If the attempt succeeds, then convert the script resource to Unicode by assuming it was encoded as UTF-8, to obtain its source.

    Let language be JavaScript.

    As with script elements, the MIME type of the script is ignored. Unlike with script elements, there is no way to override the type. It's always assumed to be JavaScript.script 要素と同様に、スクリプトの MIME 型は無視します。 script 要素とは異なり、 型を上書きする方法はありません。スクリプトは常に JavaScript と仮定します。

  4. A new script is now created, as follows.

    Create a new script execution environment set up as appropriate for the scripting language language.

    Parse/compile/initialize source using that script execution environment, as appropriate for language, and thus obtain a list of code entry-points; set the initial code entry-point to the entry-point for any executable code to be immediately run.

    Set the script's global object to worker global scope.

    Set the script's browsing context to owner browsing context.

    Set the script's document to owner document.

    Set the script's URL character encoding to UTF-8. (This is just used for encoding non-ASCII characters in the query component of URLs.)

    Set the script's base URL to url.

  5. Closing orphan workers: Start monitoring the worker such that no sooner than it stops being either a protected worker or a suspendable worker, and no later than it stops being a permissible worker, worker global scope's closing flag is set to true.

  6. 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.

  7. Jump to the script's initial code entry-point, and let that run until it either returns, fails to catch an exception, or gets prematurely aborted by the "kill a worker" or "terminate a worker" algorithms defined below.

  8. If worker global scope is actually a DedicatedWorkerGlobalScope object (i.e. the worker is a dedicated worker), then enable the port message queue of the worker's implicit port.

  9. Event loop: Wait until either there is a task in one of the event loop's task queues or worker global scope's closing flag is set to true.

  10. Run the oldest task on one of the event loop's task queues, if any. The user agent may pick any task queue.

    The handling of events or the execution of callbacks might get prematurely aborted by the "kill a worker" or "terminate a worker" algorithms defined below.

  11. If the storage mutex is now owned by the worker's event loop, release it so that it is once again free.

  12. Remove the task just run in the earlier step, if any, from its task queue.

  13. If there are any more events in the event loop's task queues or if worker global scope's closing flag is set to false, then jump back to the step above labeled event loop.

  14. If there are any outstanding transactions that have callbacks that involve scripts whose global object is the worker global scope, roll them back (without invoking any of the callbacks).

  15. Empty the worker global scope's list of active timeouts and its list of active intervals.

  16. Disentangle all the ports in the list of the worker's ports.


When a user agent is to kill 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. Set the worker's WorkerGlobalScope object's closing flag to true.

  2. If there are any tasks queued in the event loop's task queues, discard them without processing them.

  3. Wait a user-agent-defined amount of time.利用者エージェント定義の時間、待ちます。

  4. Abort the script currently running in the worker.

User agents may invoke the "kill a worker" processing model on a worker at any time, e.g. in response to user requests, in response to CPU quota management, or when a worker stops being an active needed worker if the worker continues executing even after its closing flag was set to true.


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. Set the worker's WorkerGlobalScope object's closing flag to true.

  2. If there are any tasks queued in the event loop's task queues, discard them without processing them.

  3. Abort the script currently running in the worker.労働者中で現在走っているスクリプトを停止します。

  4. 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.


The task source for the tasks mentioned above is the DOM manipulation task source.

4.6 Runtime script errors4.6 実行時スクリプト誤り

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 report the error using the WorkerGlobalScope object's onerror attribute. [HTML]

For shared workers, if the error is still not handled afterwards, or if the error occurred while handling a previous script error, the error may be reported to the user. [HTML]

For dedicated workers, if the error is still not handled afterwards, or if the error occurred while handling a previous script error, the user agent must queue a task to fire a worker error event at the Worker object associated with the worker.

When the user agent is to fire a worker error event at a Worker object, it must dispatch an event that uses the ErrorEvent interface, with the name error, that doesn't bubble and is cancelable, with its message, filename, and lineno attributes set appropriately. The default action of this event depends on whether the Worker object is itself in a worker. If it is, and that worker is also a dedicated worker, then the user agent must again queue a task to fire a worker error event at the Worker object associated with that worker. Otherwise, then the error may be reported to the user.

The task source for the tasks mentioned above is the DOM manipulation task source.


interface ErrorEvent : Event {
  readonly attribute DOMString message;
  readonly attribute DOMString filename;
  readonly attribute unsigned long lineno;
  void initErrorEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString messageArg, in DOMString filenameArg, in unsigned long linenoArg);
};

The initErrorEvent() method must initialize the event in a manner analogous to the similarly-named method in the DOM Events interfaces. [DOMEVENTS]

The message attribute represents the error message.

The filename attribute represents the absolute URL of the script in which the error originally occurred.

The lineno attribute represents the line number where the error occurred in the script.

4.7 Creating workers4.7 労働者の作成

4.7.1 The AbstractWorker abstract interface4.7.1 AbstractWorker 抽象界面

[Supplemental, NoInterfaceObject]
interface AbstractWorker {
           attribute Function onerror;

};
AbstractWorker implements EventTarget;

The following are the event handlers (and their corresponding event handler event types) that must be supported, as IDL attributes, by objects implementing the AbstractWorker interface:

Event handler Event handler event type
onerror error

4.7.2 Dedicated workers and the Worker interface

[Constructor(in DOMString scriptURL)]
interface Worker : AbstractWorker {
  void terminate();

  void postMessage(in any message, in optional MessagePortArray ports);
           attribute Function onmessage;
};

The terminate() method, when invoked, must cause the "terminate a worker" algorithm to be run on the worker with with the object is associated.

Worker 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 Worker object.

All messages received by that port must immediately be retargeted at the Worker object.

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.

The following are the event handlers (and their corresponding event handler event types) that must be supported, as IDL attributes, by objects implementing the Worker interface:

Event handler Event handler event type
onmessage message

When the Worker(scriptURL) constructor is invoked, the user agent must run the following steps:

  1. Resolve the scriptURL argument relative to the entry script's base URL, when the method is invoked.

  2. If this fails, throw a SYNTAX_ERR exception.これが失敗した場合、 SYNTAX_ERR 例外を投げます。

  3. If the origin of the resulting absolute URL is not the same as the origin of the entry script, then throw a SECURITY_ERR exception.

    Thus, scripts must be external files with the same scheme as the original page: you can't load a script from a data: URL or javascript: URL, and a https: page couldn't start workers using scripts with http: URLs.

  4. Create a new DedicatedWorkerGlobalScope object. Let worker global scope be this new object.

  5. Create a new Worker object, associated with worker global scope. Let worker be this new object.

  6. Create a new MessagePort object owned by the global object of the script that invoked the constructor. Let this be the outside port.

  7. Associate the outside port with worker.outside portworker に関連付けます。

  8. Create a new MessagePort object owned by worker global scope. Let inside port be this new object.

  9. Associate inside port with worker global scope.

  10. Entangle outside port and inside port.

  11. Return worker, and run the following steps asynchronously.worker を返し、以降の段階を非同期に走らせます。

  12. Enable outside port's port message queue.

  13. Let docs be the list of relevant Document objects to add given the global object of the script that invoked the constructor.

  14. Add to worker global scope's list of the worker's Documents the Document objects in docs.

  15. If the global object of the script that invoked the constructor is a WorkerGlobalScope object (i.e. we are creating a nested worker), add worker global scope to the list of the worker's workers of the WorkerGlobalScope object that is the global object of the script that invoked the constructor.

  16. Run a worker for the resulting absolute URL, with the script's browsing context of the script that invoked the method as the owner browsing context, with the script's document of the script that invoked the method as the owner document, with the origin of the entry script as the owner origin, and with worker global scope as the global scope.

This constructor must be visible when the script's global object is either a Window object or an object implementing the WorkerUtils interface.

4.7.3 Shared workers and the SharedWorker interface

[Constructor(in DOMString scriptURL, in optional DOMString name)]
interface SharedWorker : AbstractWorker {
  readonly attribute MessagePort port;
};

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.

When the SharedWorker(scriptURL, name) constructor is invoked, the user agent must run the following steps:

  1. Resolve the scriptURL argument.scriptURL 引数を解決します。

  2. If this fails, throw a SYNTAX_ERR exception.これが失敗した場合、 SYNTAX_ERR 例外を投げます。

  3. Otherwise, let scriptURL be the resulting absolute URL.

  4. Let name be the value of the second argument, or the empty string if the second argument was omitted.

  5. If the origin of scriptURL is not the same as the origin of the entry script, then throw a SECURITY_ERR exception.

    Thus, scripts must be external files with the same scheme as the original page: you can't load a script from a data: URL or javascript: URL, and a https: page couldn't start workers using scripts with http: URLs.

  6. Let docs be the list of relevant Document objects to add given the global object of the script that invoked the constructor.

  7. Execute the following substeps atomically:次の部分段階群を原子的に実行します。

    1. Create a new SharedWorker object, which will shortly be associated with a SharedWorkerGlobalScope object. Let this SharedWorker object be worker.

    2. Create a new MessagePort object owned by the global object of the script that invoked the method. Let this be the outside port.

    3. Assign outside port to the port attribute of worker.

    4. Let worker global scope be null.

    5. If name is not the empty string and there exists a SharedWorkerGlobalScope object whose closing flag is false, whose name attribute is exactly equal to name, and whose location attribute represents an absolute URL with the same origin as scriptURL, then let worker global scope be that SharedWorkerGlobalScope object.

    6. Otherwise, if name is the empty string and there exists a SharedWorkerGlobalScope object whose closing flag is false, and whose location attribute represents an absolute URL that is exactly equal to scriptURL, then let worker global scope be that SharedWorkerGlobalScope object.

    7. If worker global scope is not null, then run these steps:

      1. If worker global scope's location attribute represents an absolute URL that is not exactly equal to scriptURL, then throw a URL_MISMATCH_ERR exception and abort all these steps.

      2. Associate worker with worker global scope.workerworker global scope に関連付けます。

      3. Create a new MessagePort object owned by worker global scope. Let this be the inside port.

      4. Entangle outside port and inside port.

      5. Return worker and perform the next step asynchronously.worker を返し、 次の段階を非同期に実行します。

      6. Create an event that uses the MessageEvent interface, with the name connect, which does not bubble, is not cancelable, has no default action, has a data attribute whose value is the empty string and has a ports attribute whose value is an array containing only the newly created port, and queue a task to dispatch the event at worker global scope.

      7. Add to worker global scope's list of the worker's Documents the Document objects in docs.

      8. If the global object of the script that invoked the constructor is a WorkerGlobalScope object, add worker global scope to the list of the worker's workers of the WorkerGlobalScope object that is the global object of the script that invoked the constructor.

      9. Abort all these steps.これらの段階をすべて停止します。

    8. Create a new SharedWorkerGlobalScope object. Let worker global scope be this new object.

    9. Associate worker with worker global scope.workerworker global scope に関連付けます。

    10. Set the name attribute of worker global scope to name.

    11. Create a new MessagePort object owned by worker global scope. Let inside port be this new object.

    12. Entangle outside port and inside port.

  8. Return worker and perform the remaining steps asynchronously.

  9. Create an event that uses the MessageEvent interface, with the name connect, which does not bubble, is not cancelable, has no default action, has a data attribute whose value is the empty string and has a ports attribute whose value is an array containing only the newly created port, and queue a task to dispatch the event at worker global scope.

  10. Add to worker global scope's list of the worker's Documents the Document objects in docs.

  11. If the global object of the script that invoked the constructor is a WorkerGlobalScope object, add worker global scope to the list of the worker's workers of the WorkerGlobalScope object that is the global object of the script that invoked the constructor.

  12. Run a worker for scriptURL, with the script's browsing context of the script that invoked the method as the owner browsing context, with the script's document of the script that invoked the method as the owner document, with the origin of the entry script as the owner origin, and with worker global scope as the global scope.

This constructor must be visible when the script's global object is either a Window object or an object implementing the WorkerUtils interface.

The task source for the tasks mentioned above is the DOM manipulation task source.

5 APIs available to workers5 労働者が利用可能な API

[Supplemental, NoInterfaceObject]
interface WorkerUtils {
  void importScripts(in DOMString... urls);
  readonly attribute WorkerNavigator navigator;
};
WorkerUtils implements WindowTimers;

The DOM APIs (Node objects, Document objects, etc) are not available to workers in this version of this specification.DOM API (Node オブジェクト、 Document オブジェクト、その他) は、この版のこの仕様書では労働者に利用可能ではありません。

5.1 Importing scripts and libraries5.1 スクリプトとライブラリーの輸入

When a script invokes the importScripts(urls) method on a WorkerGlobalScope object, the user agent must run the following steps:

  1. If there are no arguments, return without doing anything. Abort these steps.引数がない場合、何も返さずに返ります。 これらの段階を停止します。

  2. Resolve each argument.各引数を解決します。

  3. If any fail, throw a SYNTAX_ERR exception.いずれかが失敗した場合、 SYNTAX_ERR 例外を投げます。

  4. Attempt to fetch each resource identified by the resulting absolute URLs, from the entry script's origin.

  5. For each argument in turn, in the order given, starting with the first one, run these substeps:各引数について、与えられた順に最初のものから、次の部分段階群を走らせます。

    1. Wait for the fetching attempt for the corresponding resource to complete.対応する資源を取得しようとする試みが完了するのを待ちます。

      If the fetching attempt failed, throw a NETWORK_ERR exception and abort all these steps.

      If the attempt succeeds, then convert the script resource to Unicode by assuming it was encoded as UTF-8, to obtain its source.

      Let language be JavaScript.

      As with the worker's script, the script here is always assumed to be JavaScript, regardless of the MIME type.労働者のスクリプトと同じく、ここでのスクリプトも、 MIME 型に関わらず常に JavaScript であるとみなします。

    2. Create a script, using source as the script source and language as the scripting language, using the same global object, browsing context, URL character encoding, base URL, and script group as the script that was created by the worker's run a worker algorithm.

      Let the newly created script run until it either returns, fails to parse, fails to catch an exception, or gets prematurely aborted by the "kill a worker" or "terminate a worker" algorithms defined above.

      If it failed to parse, then throw an ECMAScript SyntaxError exception and abort all these steps. [ECMA262]

      If an exception was raised or if the script was prematurely aborted, then abort all these steps, letting the exception or aborting continue to be processed by the script that called the importScripts() method.

      If the "kill a worker" or "terminate a worker" algorithms abort the script then abort all these steps.

5.2 The WorkerNavigator object

The navigator attribute of the WorkerUtils interface must return an instance of the WorkerNavigator interface, which represents the identity and state of the user agent (the client):

interface WorkerNavigator {};
WorkerNavigator implements NavigatorID;
WorkerNavigator implements NavigatorOnLine;

Objects implementing the WorkerNavigator interface also implement the NavigatorID and NavigatorOnLine interfaces. [HTML]

This WorkerNavigator interface must not exist if the interface's relevant namespace object is a Window object. [WEBIDL]

5.3 APIs defined in other specifications5.3 他の仕様書で定義されている API

The openDatabase() and openDatabaseSync() methods are defined in the Web SQL Database specification. [WEBSQL]

5.4 Interface objects and constructors5.4 界面オブジェクトと構築器

There must be no interface objects and constructors available in the global scope of scripts whose script's global object is a WorkerGlobalScope object except for the following:

These requirements do not override the requirements defined by the Web IDL specification, in particular concerning the visibility of interfaces annotated with the [NoInterfaceObject] extended attribute.

5.5 Worker locations5.5 労働者の所在

interface WorkerLocation {
  readonly attribute DOMString href;
  readonly attribute DOMString protocol;
  readonly attribute DOMString host;
  readonly attribute DOMString hostname;
  readonly attribute DOMString port;
  readonly attribute DOMString pathname;
  readonly attribute DOMString search;
  readonly attribute DOMString hash;
};

A WorkerLocation object represents an absolute URL set at its creation.

The href attribute must return the absolute URL that the object represents.

The WorkerLocation interface also has the complement of URL decomposition IDL attributes, protocol, host, port, hostname, pathname, search, and hash. These must follow the rules given for URL decomposition IDL attributes, with the input being the absolute URL that the object represents (same as the href attribute), and the common setter action being a no-op, since the attributes are defined to be readonly. [HTML]

The WorkerLocation interface must not exist if the interface's relevant namespace object is a Window object. [WEBIDL]

References参照

All references are normative unless marked "Non-normative".

[DOMCORE]
Document Object Model (DOM) Level 3 Core Specification, A. Le Hors, P. Le Hegaret, L. Wood, G. Nicol, J. Robie, M. Champion, S. Byrnes. W3C.
[DOMEVENTS]
Document Object Model (DOM) Level 3 Events Specification, D. Schepers. W3C.
[ECMA262]
ECMAScript Language Specification. ECMA.
[HTML]
HTML, I. Hickson. WHATWG.
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels, S. Bradner. IETF.
[WEBIDL]
Web IDL, C. McCormack. W3C.
[WEBSQL]
Web SQL Database, I. Hickson. W3C.
[XHR]
XMLHttpRequest, A. van Kesteren. W3C.

Acknowledgements謝辞

Thanks to Aaron Boodman, Алексей Проскуряков (Alexey Proskuryakov), Anne van Kesteren, Ben Turner, Dmitry Titov, Drew Wilson, Jeremy Orlow, Jonas Sicking, Justin James, Kevin Hakanson, Maciej Stachowiak, Michael Nordman, Mike Smith, and Philip Taylor for their useful and substantial comments.Aaron Boodman, Алексей Проскуряков (Alexey Proskuryakov), Anne van Kesteren, Ben Turner, Dmitry Titov, Drew Wilson, Jeremy Orlow, Jonas Sicking, Justin James, Kevin Hakanson, Maciej Stachowiak, Michael Nordman, Mike Smith, Philip Taylor の有用かつ重要なコメントに感謝します。

Huge thanks to the whole Gears team, who pioneered this technology and whose experience has been a huge influence on this specification.Gears チームの方々にも非常に感謝します。 Gears チームの方々はこの技術を開拓し、その経験はこの仕様書にも多大な影響を与えています。