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.
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.
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 unoptimised search for a prime number. The postMessage() method is used to send a
  message back to the page when a prime is found.
This section is non-normative.
In this example, the main document uses two workers, one for fetching stock updates at regular intervals, and one for performing search queries that the user requests.
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>
  <meta http-equiv="Refresh" content="120; URL=../">
 </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));
};
  
  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!');
}
  
  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
  }
}
  
  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');
  }
}
  
  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)[0];
     // 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';
         context.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)[0];
     var message = event.data.substr(4 + name.length + 1);
     // 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
   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];
     // 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>
  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.
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 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;
  }
}
  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.
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.
This section is non-normative.
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');
  This section is non-normative.
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.
To receive messages from a dedicated worker, use the onmessage event
  handler IDL attribute on the Worker object:
worker.onmessage = function (event) { ... };
  You can also use the addEventListener()
  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.
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, // an ArrayBuffer object
  threshold: 0.6,
}, [buffer]);
  To receive a message inside the worker, the onmessage event handler IDL attribute is used.
onmessage = function (event) { ... };
  You can again also use the addEventListener() method.
In either case, the data is provided in the event object's data attribute.
To send messages back, you again use postMessage(). It supports the
  structured data in the same manner.
postMessage(event.data.input, [event.data.input]); // transfer the buffer back
This section is non-normative.
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.
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.
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');
  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']});
  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;
  // set up a listener
  newPort.onmessage = function (event) { ... };
  // send a message back to the port
  newPort.postMessage('ready!'); // can also send structured data, of course
};
  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.
The global scope is the "inside" of a worker.
WorkerGlobalScope common interface[Exposed=Worker] 
interface WorkerGlobalScope : EventTarget {
  readonly attribute WorkerGlobalScope self;
  readonly attribute WorkerLocation location;
  void close();
  attribute OnErrorEventHandler onerror;
  attribute EventHandler onlanguagechange;
  attribute EventHandler onoffline;
  attribute EventHandler ononline;
};
  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 initialise 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):
Discard any tasks that have been added to the
   WorkerGlobalScope object's event loop's task
   queues.
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 event handler IDL attributes,
  by objects implementing the WorkerGlobalScope interface:
| Event handler | Event handler event type | 
|---|---|
| onerror | error | 
| onlanguagechange | languagechange | 
| onoffline | offline | 
| ononline | online | 
For data: URLs, this is the
  origin specified by the entry settings object when the constructor was
  called. For other URLs, this is the origin of the value of
  the absolute URL given in the worker's location attribute.
DedicatedWorkerGlobalScope interface[Global=(Worker,DedicatedWorker),Exposed=DedicatedWorker]
/*sealed*/ interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
  void postMessage(any message, optional sequence<Transferable> transfer);
  attribute EventHandler 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 event
  handler 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.
SharedWorkerGlobalScope interface[Global=(Worker,SharedWorker),Exposed=SharedWorker]
/*sealed*/ interface SharedWorkerGlobalScope : WorkerGlobalScope {
  readonly attribute DOMString name;
  readonly attribute ApplicationCache applicationCache;
  attribute EventHandler onconnect;
};
  Shared workers receive message ports through connect events on their SharedWorkerGlobalScope object for each
  connection.
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 event
  handler 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.
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.
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 background operations are dropped, etc.
Workers communicate with other workers and with browsing
  contexts through message channels and their
  MessagePort objects.
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 q 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 settings object o when creating or obtaining a
  worker, the list of relevant Document objects to add depends on the type
  of global object specified by o's. If o
  specifies a global object that is a WorkerGlobalScope object (i.e. if we
  are creating a nested worker), then the relevant Documents are the the worker's
  Documents of the global object specified by o. Otherwise, o specifies a global object that
  is a Window object, and the relevant Document is just the
  responsible document specified by o.
A worker is said to be a permissible worker if its list of the worker's
  Documents is not empty, or if its list has been empty for no more than a short
  user-agent-defined timeout value, its WorkerGlobalScope is actually a
  SharedWorkerGlobalScope object (i.e. the worker is a shared worker), and the user
  agent has a browsing context whose Document is not complete
  loaded.
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.
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 protected worker if it is an active needed
  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 a suspendable worker if it is not an active needed worker but it is a permissible worker.
When a user agent is to run a worker for a script with URL url, an environment settings object settings object, and a referrer source parent referrer source it must run the following steps:
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.
For the purposes of timing APIs, this is the official moment of creation of the worker.
Let worker global scope be the global object specified by settings object.
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.
Attempt to fetch the resource identified by url, from the origin specified by settings object, using parent referrer source as the referrer source (not using the referrer source specified by settings object!), and with the blocking flag set and the force same-origin flag set.
If the attempt fails, 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 let source be the result of running the UTF-8 decode algorithm on the script resource.
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.
In the newly created execution environment, create a JavaScript global
   environment whose global object is worker global scope. If worker
   global scope is a DedicatedWorkerGlobalScope object, then this is a
   dedicated worker environment. Otherwise, worker global scope is a
   SharedWorkerGlobalScope object, and this is a shared worker
   environment. (In either case, by definition, it is a worker
   environment.)
Let script be a new script.
Obtain the appropriate script execution environment for the scripting language language from settings object.
Parse/compile/initialise source using that script execution environment, as appropriate for language, and thus obtain a code entry-point. If the script was not compiled successfully, let the code entry-point be a no-op script, and act as if a corresponding uncaught script error had occurred.
Let script's settings object be settings object.
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.
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.
Jump to the script's 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.
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.
Event loop: Run the responsible event loop specified by settings object until it is destroyed.
The handling of events or the execution of callbacks by tasks run by the event loop might get prematurely aborted by the "kill a worker" or "terminate a worker" algorithms defined below.
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.
Empty the worker global scope's list of active timers.
Disentangle all the ports in the list of the worker's ports.
Empty the worker's list of
    the worker's Documents.
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):
Set the worker's WorkerGlobalScope object's closing flag to true.
If there are any tasks queued in the
   WorkerGlobalScope object's event loop's task
   queues, discard them without processing them.
Wait a user-agent-defined amount of time.
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):
Set the worker's WorkerGlobalScope object's closing flag to true.
If there are any tasks queued in the
   WorkerGlobalScope object's event loop's task
   queues, discard them without processing them.
Abort the script currently running in the worker.
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.
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 for that script, with the position (line number
  and column number) where the error occurred, using the WorkerGlobalScope object as
  the target.
For shared workers, if the error is still not handled afterwards, the error may be reported to the user.
For dedicated workers, if the error is still not
  handled afterwards, the user agent must queue a task to fire a trusted
  event that uses the ErrorEvent interface, with the name error, that doesn't bubble and is cancelable, with its message, filename, lineno, colno,
  attributes initialised appropriately, and with the error attribute initialised to null, at the
  Worker object associated with the worker. If the event is not canceled, 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.
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.
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.
The task source for the task mentioned above is the DOM manipulation task source.
AbstractWorker abstract interface[NoInterfaceObject, Exposed=(Window,Worker)]
interface AbstractWorker {
  attribute EventHandler onerror;
};
  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 type | 
|---|---|
| onerror | error | 
When the user agent is required to set up a worker environment settings object, given a worker global scope and a URL script address it must run the following steps:
Let inherited responsible browsing context be the responsible browsing context specified by the incumbent settings object.
Let inherited origin be the origin specified by the incumbent settings object.
Let worker event loop be a newly created event loop.
Let settings object be a new environment settings object whose algorithms are defined as follows:
When the environment settings object is created, for each language supported by the user agent, create an appropriate execution environment as defined by the relevant specification.
When a script execution environment is needed, return the appropriate one from those created when the environment settings object was created.
Currently, workers only support JavaScript, so only a JavaScript execution environment is actually needed here.
Return worker global scope.
Return inherited responsible browsing context.
Return worker event loop.
Not applicable (the responsible event loop is not a browsing context event loop).
Return script address.
Return UTF-8.
Return script address.
Return inherited origin.
Return settings object.
Worker interface[Constructor(DOMString scriptURL), Exposed=(Window,Worker)]
interface Worker : EventTarget {
  void terminate();
  void postMessage(any message, optional sequence<Transferable> transfer);
  attribute EventHandler onmessage;
};
Worker implements AbstractWorker;
  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 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 postMessage()
   method's first argument can be structured data:
worker.postMessage({opcode: 'activate', device: 1938, parameters: [23, 102]});
  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 type | 
|---|---|
| onmessage | message | 
When the Worker(scriptURL) constructor
  is invoked, the user agent must run the following steps:
  
The user agent may throw a SecurityError exception and abort these steps if
   the request violates a policy decision (e.g. if the user agent is configured to not allow the
   page to start dedicated workers).
Resolve the scriptURL argument relative to the API base URL specified by the entry settings object when the method was invoked.
If this fails, throw a SyntaxError exception and abort these steps.
Let worker URL be the resulting absolute URL.
If the scheme component of worker URL is
    not "data", and the origin of worker
    URL is not the same as the origin specified
    by the incumbent settings object, then throw a SecurityError exception
    and abort these steps.
For example, scripts can be external files with the same scheme, host, and port
    as the original page, or data: URLs, or
    same-origin blob: URLs. Thus, an https: page couldn't start workers using scripts with http: URLs. [FILEAPI].
Create a new DedicatedWorkerGlobalScope object. Let worker global
   scope be this new object.
Set up a worker environment settings object with worker global scope and worker URL, and let settings object be the result.
Create a new Worker object, associated with worker global scope.
   Let worker be this new object.
Create a new MessagePort object whose owner is the incumbent settings object. Let this
   be the outside port.
Associate the outside port with worker.
Create a new MessagePort object whose owner is settings object. Let inside
   port be this new object.
Associate inside port with worker global scope.
Entangle outside port and inside port.
Return worker, and run the following steps in parallel.
Enable outside port's port message queue.
Let docs be the list of relevant Document objects to
   add given the incumbent settings object.
Add to worker global
   scope's list of the worker's Documents the
   Document objects in docs.
If the global object specified by the incumbent settings object
   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 specified by the
   incumbent settings object.
Run a worker for the script with URL worker URL, the environment settings object settings object, and with the referrer source specified by the incumbent settings object.
SharedWorker interface[Constructor(DOMString scriptURL, optional DOMString name), Exposed=(Window,Worker)]
interface SharedWorker : EventTarget {
  readonly attribute MessagePort port;
};
SharedWorker implements AbstractWorker;
  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:
The user agent may throw a SecurityError exception and abort these steps if
   the request violates a policy decision (e.g. if the user agent is configured to not allow the
   page to start shared workers).
Resolve the scriptURL argument.
If this fails, throw a SyntaxError exception and abort these steps.
Let scriptURL be the resulting absolute URL and parsed scriptURL be the resulting parsed URL.
Let name be the value of the second argument, or the empty string if the second argument was omitted.
If the scheme component of parsed
    scriptURL is not "data", and the origin
    of scriptURL is not the same as the
    origin specified by the incumbent settings object, then throw a
    SecurityError exception and abort these steps.
Thus, scripts must either be external files with the same scheme, host, and port
    as the original page, or data: URLs. For
    example, an https: page couldn't start workers using
    scripts with http: URLs.
Let docs be the list of relevant Document objects to
    add given the incumbent settings object.
Execute the following substeps atomically:
Create a new SharedWorker object, which will shortly be associated with a
     SharedWorkerGlobalScope object. Let this SharedWorker object be worker.
Create a new MessagePort object whose owner is the incumbent settings object. Let
     this be the outside port.
Assign outside port to the port attribute of worker.
Let worker global scope be null.
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 that is the global object specified by an environment
      settings object that specifies as its origin the same origin
      as the origin of scriptURL, then let worker global scope be
      that SharedWorkerGlobalScope object.
Otherwise, if name is the empty string and there exists a
      SharedWorkerGlobalScope object whose closing flag is false, whose name attribute is the empty string, and whose
      location attribute represents an
      absolute URL that is exactly equal to scriptURL, then let worker
      global scope be that SharedWorkerGlobalScope object.
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 objects are the incumbent settings object, then set worker global scope to null.
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 steps:
If worker global scope's location attribute represents an absolute
       URL that is not exactly equal to scriptURL, then throw a
       URLMismatchError exception and abort all these steps.
Associate worker with worker global scope.
Let settings object be the environment settings object whose global object is worker global scope.
Create a new MessagePort object whose owner is settings object. Let this be
       the inside port.
Entangle outside port and inside port.
Create a trusted 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 initialised to the empty string, has a ports attribute whose value is initialised to a read only array containing only the newly created port,
       and has a source attribute whose value is
       initialised to the newly created port, and queue a task to dispatch the event at worker global
       scope.
Add to worker global
        scope's list of the worker's Documents the
        Document objects in docs.
If the global object specified by the incumbent settings object
        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 specified by the incumbent settings
        object.
Return worker and abort all these steps.
Create a new SharedWorkerGlobalScope object. Let worker
     global scope be this new object.
Set up a worker environment settings object with worker global scope and scriptURL, and let settings object be the result.
Associate worker with worker global scope.
Set the name attribute of
     worker global scope to name.
Create a new MessagePort object whose owner is settings object. Let inside
     port be this new object.
Entangle outside port and inside port.
Return worker and perform the remaining steps in parallel.
Create a trusted 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 initialised to the empty string, has a ports attribute whose value is initialised to a read only array containing only the newly created port, and
   has a source attribute whose value is initialised
   to the newly created port, and queue a task to dispatch the event at worker global
   scope.
Add to worker global
    scope's list of the worker's Documents the
    Document objects in docs.
If the global object specified by the incumbent settings object 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 specified by the incumbent settings object.
Run a worker for the script with URL scriptURL, the environment settings object settings object, and with the referrer source specified by the incumbent settings object.
The task source for the tasks mentioned above is the DOM manipulation task source.
[Exposed=Worker]
partial interface WorkerGlobalScope { // not obsolete
  void importScripts(DOMString... urls);
  readonly attribute WorkerNavigator navigator;
};
WorkerGlobalScope implements WindowTimers;
WorkerGlobalScope implements WindowBase64;
  When a script invokes the importScripts(urls) method on a WorkerGlobalScope object, the user
  agent must run the following steps:
If there are no arguments, return without doing anything. Abort these steps.
Let settings object be the incumbent settings object.
Resolve each argument.
If any fail, throw a SyntaxError exception and abort these steps.
Attempt to fetch each resource identified by the resulting absolute URLs, from the origin specified by settings object, using the referrer source specified by settings object, and with the blocking flag set.
For each argument in turn, in the order given, starting with the first one, run these substeps:
Wait for the fetching attempt for the corresponding resource to complete.
If the fetching attempt failed (e.g. the server
      returned a 4xx or 5xx status code or
      equivalent, or there was a DNS error), throw a NetworkError exception and abort all
      these steps.
If the attempt succeeds, then let source be the result of running the UTF-8 decode algorithm on the script resource.
Let language be JavaScript.
As with the worker's script, the script here is always assumed to be JavaScript, regardless of the MIME type.
Create a script using source as the script source, the URL from which source was obtained, language as the scripting language, and settings object as the environment settings object.
If the script came from a resource whose URL does not have the same origin as the origin specified by the incumbent settings object, then pass the muted errors flag to the create a script algorithm as well.
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 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.
If the "kill a worker" or "terminate a worker" algorithms abort the script then abort all these steps.
WorkerNavigator objectThe 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 {};
WorkerNavigator implements NavigatorID;
WorkerNavigator implements NavigatorLanguage;
WorkerNavigator implements NavigatorOnLine;
  [Exposed=Worker]
interface WorkerLocation { };
WorkerLocation implements URLUtilsReadOnly;
  A WorkerLocation object represents an absolute URL set at its
  creation.
The WorkerLocation interface supports the URLUtilsReadOnly
  interface. [URL]
When the object is created, the user agent must invoke the element's
  URLUtilsReadOnly interface's set the
  input algorithm with the absolute URL that the WorkerLocation
  object represents as the given value.
The element's URLUtilsReadOnly interface's get the base algorithm must return null.