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.

Status of This document

This section describes the status of this document at the
time of its publication. Other documents may supersede this
document. A list of current W3C publications and the
latest
revision of this technical report can be found in the W3C technical reports index at
http://www.w3.org/TR/.

Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

The W3C Web Applications Working Group is the W3C working group responsible for this specification's progress along the W3C Recommendation track. The Working Group expects to advance this specification to Recommendation status.

1 Introduction

1.1 Scope

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 Examples

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 worker

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

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.

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.

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

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.

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.

1.2.5 Delegation

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.

1.3 Tutorials

1.3.1 Creating a dedicated worker

Creating a worker requires a URL to a JavaScript file. The Worker() constructor is invoked with the
URL to that file as its only argument; a worker is then created and
returned:

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

1.3.2 Communicating with a dedicated worker

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

1.3.3 Shared workers

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.

2 Conformance requirements

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]

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 Dependencies

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 Terminology

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

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. [DOM]

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 Infrastructure

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.

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):

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

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.

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.

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.

4.2 The event loop

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.

4.3 The worker's lifetime

Workers communicate with other workers and with browsing contexts through message channels and their
MessagePort objects.

Each WorkerGlobalScopeworker 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 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 objecto 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.

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.

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

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.

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):

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.

4.5 Runtime script errors

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.

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

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 URLworker URL,
the environment settings objectsettings object, and with incumbent settings object's creation URL.

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.

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.

Create a new MessagePort object whose owner is settings object. Let this be
the inside port.

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

Create a new MessagePort object whose owner is settings object. Let inside port be this new object.

Entangleoutside 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 initialized
to the newly created port, and queue a task to dispatch the event at worker global
scope.

To postprocess the fetch result, the user agent must throw a NetworkError exception and abort all these steps if the fetching attempt failed (e.g. the server returned a 4xx or 5xx status, or there was a DNS error).

The import scripts into worker global scope algorithm has three hooks for algorithm steps that may be customized by any callers: validate the state, get a fetch result, and postprocess the fetch result.

To import scripts into worker global scope, the user agent must run the following steps:

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.

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.