Living Standard — Last Updated 2 June 2023
Support in all current engines.
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 lang = "en" >
< head >
< meta charset = "utf-8" >
< 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. The postMessage()
method is used to send a
message back to the page when a prime is found.
This section is non-normative.
All of our examples so far show workers that run classic
scripts. Workers can instead be instantiated using module
scripts, which have the usual benefits: the ability to use the JavaScript
import
statement to import other modules; strict mode by default; and
top-level declarations not polluting the worker's global scope.
As the import
statement is available, the importScripts()
method will automatically fail
inside module workers.
In this example, the main document uses a worker to do off-main-thread image manipulation. It imports the filters used from another module.
The main page is as follows:
<!DOCTYPE html>
< html lang = "en" >
< meta charset = "utf-8" >
< title > Worker example: image decoding</ title >
< p >
< label >
Type an image URL to decode
< input type = "url" id = "image-url" list = "image-list" >
< datalist id = "image-list" >
< option value = "https://html.spec.whatwg.org/images/drawImage.png" >
< option value = "https://html.spec.whatwg.org/images/robots.jpeg" >
< option value = "https://html.spec.whatwg.org/images/arcTo2.png" >
</ datalist >
</ label >
</ p >
< p >
< label >
Choose a filter to apply
< select id = "filter" >
< option value = "none" > none</ option >
< option value = "grayscale" > grayscale</ option >
< option value = "brighten" > brighten by 20%</ option >
</ select >
</ label >
</ p >
< div id = "output" ></ div >
< script type = "module" >
const worker = new Worker( "worker.js" , { type: "module" });
worker. onmessage = receiveFromWorker;
const url = document. querySelector( "#image-url" );
const filter = document. querySelector( "#filter" );
const output = document. querySelector( "#output" );
url. oninput = updateImage;
filter. oninput = sendToWorker;
let imageData, context;
function updateImage() {
const img = new Image();
img. src = url. value;
img. onload = () => {
const canvas = document. createElement( "canvas" );
canvas. width = img. width;
canvas. height = img. height;
context = canvas. getContext( "2d" );
context. drawImage( img, 0 , 0 );
imageData = context. getImageData( 0 , 0 , canvas. width, canvas. height);
sendToWorker();
output. replaceChildren( canvas);
};
}
function sendToWorker() {
worker. postMessage({ imageData, filter: filter. value });
}
function receiveFromWorker( e) {
context. putImageData( e. data, 0 , 0 );
}
</ script >
The worker file is then:
import * as filters from "./filters.js" ;
self. onmessage = e => {
const { imageData, filter } = e. data;
filters[ filter]( imageData);
self. postMessage( imageData, [ imageData. data. buffer]);
};
Which imports the file filters.js
:
export function none() {}
export function grayscale({ data: d }) {
for ( let i = 0 ; i < d. length; i += 4 ) {
const [ r, g, b] = [ d[ i], d[ i + 1 ], d[ i + 2 ]];
// CIE luminance for the RGB
// The human eye is bad at seeing red and blue, so we de-emphasize them.
d[ i] = d[ i + 1 ] = d[ i + 2 ] = 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
};
export function brighten({ data: d }) {
for ( let i = 0 ; i < d. length; ++ i) {
d[ i] *= 1.2 ;
}
};
Support in all current engines.
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>
< html lang = "en" >
< meta charset = "utf-8" >
< 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>
< html lang = "en" >
< meta charset = "utf-8" >
< 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
traversable.
Here is the outer HTML page:
<!DOCTYPE HTML>
< html lang = "en" >
< meta charset = "utf-8" >
< 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>
< html lang = "en" >
< meta charset = "utf-8" >
< 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 lang = "en" >
< head >
< meta charset = "utf-8" >
< 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 lang = "en" >
< head >
< meta charset = "utf-8" >
< 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 lang = "en" >
< head >
< meta charset = "utf-8" >
< 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.
Suppose that a cryptography library is made available that provides three tasks:
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 lang = "en" >
< head >
< meta charset = "utf-8" >
< title > Worker example: Crypto library</ title >
< script >
const cryptoLib = new Worker( 'libcrypto-v1.js' ); // or could use 'libcrypto-v2.js'
function startConversation( source, message) {
const messageChannel = new MessageChannel();
source. postMessage( message, [ messageChannel. port2]);
return messageChannel. port1;
}
function getKeys() {
let state = 0 ;
startConversation( cryptoLib, "genkeys" ). onmessage = function ( e) {
if ( state === 0 )
document. getElementById( 'public' ). value = e. data;
else if ( state === 1 )
document. getElementById( 'private' ). value = e. data;
state += 1 ;
};
}
function enc() {
const port = startConversation( cryptoLib, "encrypt" );
port. postMessage( document. getElementById( 'public' ). value);
port. postMessage( document. getElementById( 'input' ). value);
port. onmessage = function ( e) {
document. getElementById( 'input' ). value = e. data;
port. close();
};
}
function dec() {
const port = startConversation( cryptoLib, "decrypt" );
port. postMessage( document. getElementById( 'private' ). value);
port. postMessage( document. getElementById( 'input' ). value);
port. onmessage = function ( e) {
document. getElementById( 'input' ). value = e. data;
port. close();
};
}
</ script >
< style >
textarea { display : block ; }
</ style >
</ head >
< body onload = "getKeys()" >
< fieldset >
< legend > Keys</ legend >
< p >< label > Public Key: < textarea id = "public" ></ textarea ></ label ></ p >
< p >< label > Private Key: < textarea id = "private" ></ textarea ></ label ></ p >
</ fieldset >
< p >< label > Input: < textarea id = "input" ></ textarea ></ label ></ p >
< p >< button onclick = "enc()" > Encrypt</ button > < button onclick = "dec()" > Decrypt</ button ></ p >
</ body >
</ html >
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.
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' );
If you want your worker script to be interpreted as a module script instead of the default classic script, you need to use a slightly different signature:
var worker = new Worker( 'helper.mjs' , { type: "module" });
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) { ... };
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 To receive a message inside the worker, the You can again also use the In either case, the data is provided in the event object's To send messages back, you again use Support in all current engines. 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 Communicating with shared workers is done with explicit Inside the shared worker, new clients of the worker are announced using the This standard defines two kinds of workers: dedicated workers, and shared workers. Dedicated
workers, once created, are linked to their creator, but message ports can be used to communicate
from a dedicated worker to multiple other browsing contexts or workers. Shared workers, on the
other hand, are named, and once created any script running in the same origin can
obtain a reference to that worker and communicate with it. Service Workers defines a
third kind. [SW] The global scope is the "inside" of a worker. Support in all current engines. A It is a set, instead of a single owner, to accommodate
A A A The name can have different
semantics for each subclass of A A A A Support in all current engines. Support in all current engines. Support in all current engines. WorkerGlobalScope/importScripts Support in all current engines. The The While the 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
Support in all current engines. WorkerGlobalScope/languagechange_event Support in all current engines. WorkerGlobalScope/offline_event WorkerGlobalScope/online_event Support in all current engines. All messages received by that port must immediately be retargeted at the
DedicatedWorkerGlobalScope/name Support in all current engines. Returns dedicatedWorkerGlobal's name, i.e. the value given to the
DedicatedWorkerGlobalScope/postMessage Support in all current engines. Clones message and transmits it to the DedicatedWorkerGlobalScope/close Support in all current engines. Aborts dedicatedWorkerGlobal. The The To close a worker, given a workerGlobal, run these steps: Discard any tasks that have been added to
workerGlobal's relevant agent's event loop's task
queues. Set workerGlobal's closing
flag to true. (This prevents any further tasks from being queued.) The 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/message_event Support in all current engines. DedicatedWorkerGlobalScope/messageerror_event Support in all current engines. Support in all current engines. A Shared workers receive message ports through Support in all current engines. Returns sharedWorkerGlobal's name, i.e. the value given to the
Support in all current engines. Aborts sharedWorkerGlobal. The The 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/connect_event Support in all current engines. A worker event loop's task queues only have
events, callbacks, and networking activity as tasks. These worker event loops are created by the
run a worker algorithm. Each Once the Workers communicate with other workers and with Each Given an environment settings
object o when creating or obtaining a worker, the relevant owner to
add depends on the type of global
object specified by o. If o's global object is a A worker is said to be a permissible worker if its 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 its owners are either 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 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 Let is shared be true if worker is a Let owner be the relevant owner to add given outside
settings. Let parent worker global scope be null. If owner is a Let unsafeWorkerCreationTime be the unsafe shared current
time. Let agent be the result of obtaining a dedicated/shared worker agent given outside settings and
is shared. Run the rest of these steps in that agent. Let realm execution context be the result of creating a new realm
given agent and the following customizations: For the global object, if is shared is true, create a new
Let worker global scope be the global
object of realm execution context's Realm component.
This is the Set up a worker environment settings object with realm execution
context, outside settings, and unsafeWorkerCreationTime, and let
inside settings be the result. Set worker global scope's name to the value of options's
If is shared is true, then: Set worker global scope's constructor origin to
outside settings's origin. Set worker global scope's constructor url to
url. Set worker global scope's type to the value of options's
Set worker global scope's credentials to the value of
options's Let destination be " Obtain script by switching on the value of options's In both cases, let performFetch be the following perform the fetch hook given request,
isTopLevel and processCustomFetchResponse: If isTopLevel is false, fetch
request with processCustomFetchResponse, and abort these steps. Fetch request with response response and null, failure,
or a byte sequence bodyBytes: Initialize worker global scope's
policy container given worker global scope, response, and
inside settings. If the Run CSP initialization for a global object algorithm returns
" If worker global scope's embedder policy's value is compatible with cross-origin
isolation and is shared is true, then set agent's agent
cluster's cross-origin isolation
mode to " This really ought to be set when the agent cluster is created, which requires
a redesign of this section. If the result of checking a
global object's embedder policy with worker global scope, outside
settings, and response is false, then set response to a
network error. Set worker global scope's cross-origin isolated
capability to true if agent's agent cluster's cross-origin isolation mode is " If is shared is false and owner's cross-origin isolated
capability is false, then set worker global scope's cross-origin isolated
capability to false. If is shared is false and response's
url's scheme is " This is a conservative default for now, while we figure out how workers in
general, and Run processCustomFetchResponse with response and
bodyBytes. In both cases, let onComplete given script be the following steps: If script is null or if script's error to rethrow is non-null, then: Queue a global task on the DOM manipulation task source given
worker's relevant global object to fire an event named Run the environment discarding steps
for inside settings. Abort these steps. Associate worker with worker global scope. Let inside port be a new Associate inside port with worker global scope. Entangle outside port and inside port. Create a new 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. Set inside settings's execution ready flag. If script is a classic script, then run the classic script script. Otherwise, it is a module
script; run the module script
script. In addition to the usual possibilities of returning a value or failing due to
an exception, this could be prematurely aborted by
the terminate a worker algorithm defined below. Enable outside port's port message queue. If is shared is false, enable the port message queue
of the worker's implicit port. If is shared is true, then queue a global task on DOM
manipulation task source given worker global scope to fire an event named Enable the client message queue of the
Event loop: Run the responsible
event loop specified by inside settings 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 terminate a
worker algorithm 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. Clear the worker global scope's
map of active timers. Disentangle all the ports in the list of the worker's ports. 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 If there are any tasks queued in the
Abort the script currently running in the
worker. If the worker's User agents may invoke the terminate a worker algorithm when a worker stops being
an active needed worker and the worker continues executing even after its closing flag was set to true. 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 For shared workers, if the error is still not handled
afterwards, the error may be reported to a developer console. For dedicated workers, if the error is still not
handled afterwards, the user agent must queue a
task to run these steps: Let notHandled be the result of firing an
event named If notHandled is true, then the user agent must act as if the uncaught runtime
script error had occurred in the global scope that the If the implicit port connecting the worker to its Thus, error reports propagate up to
the chain of dedicated workers up to the original The task source for the task mentioned above is the DOM manipulation
task source. 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
Support in all current engines. Support in all current engines. Support in all current engines. To set up a worker environment settings object, given a JavaScript execution
context execution context, an environment settings object
outside settings, and a number unsafeWorkerCreationTime: Let inherited origin be outside settings's origin. Let realm be the value of execution context's Realm
component. Let worker global scope be realm's global object. Let settings object be a new environment settings object whose algorithms
are defined as follows: Return execution context.
Return worker global scope's module map. Return UTF-8. Return worker global scope's url. Return a unique opaque origin if worker
global scope's url's scheme is " Return worker global scope's policy container. Return worker global scope's cross-origin isolated
capability. Return the result of coarsening
unsafeWorkerCreationTime with worker global scope's cross-origin isolated
capability. Set settings object's id to a new
unique opaque string, creation URL to
worker global scope's url, top-level creation URL to null,
target browsing context to
null, and active service worker
to null. If worker global scope is a Otherwise, set settings object's top-level origin to an
implementation-defined value. See Client-Side
Storage Partitioning for the latest on properly defining this. Set realm's [[HostDefined]] field to settings object. Return settings object. Support in all current engines. Support in all current engines. Returns a new Support in all current engines. Support in all current engines. Clones message and transmits it to worker's global environment.
transfer can be passed as a list of objects that are to be transferred rather than
cloned. The All messages received by that port must immediately be retargeted at the The The 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 When the The user agent may throw a " Let outside settings be the current settings object. Parse the scriptURL argument relative to
outside settings. If this fails, throw a " Any same-origin URL (including Let worker be a new Let outside port be a new Associate the outside port with worker. Run this step in parallel: Run a worker given worker, worker URL, outside
settings, outside port, and options. Return worker. Support in all current engines. Support in all current engines. Returns a new Returns a new Support in all current engines. Returns sharedWorker's The A user agent has an associated shared worker manager which is the result of
starting a new parallel queue. Each user agent has a single shared worker manager for simplicity.
Implementations could use one per origin; that would not be observably different and
enables more concurrency. When the Optionally, throw a " If options is a Let outside settings be the current settings object. Parse scriptURL relative to outside
settings. If this fails, throw a " Any same-origin URL (including Let worker be a new Let outside port be a new Assign outside port to the Let callerIsSecureContext be true if outside settings is a
secure context; otherwise, false. Let outside storage key be the result of running obtain a storage key
for non-storage purposes given outside settings. Enqueue the following steps to the shared worker manager: Let worker global scope be null. For each scope in the list of all
Let worker storage key be the result of running obtain a storage
key for non-storage purposes given scope's relevant settings
object. If all of the following conditions are true: then: Set worker global scope to scope. If worker global scope is not null, but the user agent has been
configured to disallow communication between the worker represented by the worker global
scope and the scripts whose settings object is outside settings, then set worker global
scope to null. For example, a user agent could have a development mode that isolates a
particular top-level traversable from all other pages, and scripts in that
development mode could be blocked from connecting to shared workers running in the normal
browser mode. If worker global scope is not null, then check if worker global
scope's type and credentials match the
options values. If not, queue a task to fire an event named If worker global scope is not null, then run these subsubsteps: Let settings object be the relevant settings object for
worker global scope. Let workerIsSecureContext be true if settings object is a
secure context; otherwise, false. If workerIsSecureContext is not callerIsSecureContext, then
queue a task to fire an event named
Associate worker with worker global scope. Let inside port be a new Entangle outside port and inside port. Queue a task, using the DOM manipulation task source, to
fire an event named Append the relevant owner to add given
outside settings to worker global scope's owner
set. Otherwise, in parallel, run a worker given worker,
urlRecord, outside settings, outside port, and
options. Return worker. Returns the number of logical processors potentially available to the user agent.
User agents should err toward exposing the number of logical processors available, using lower
values only in cases where there are user-agent specific limits in place (such as a limitation
on the number of workers that can be created) or when the user agent
desires to limit fingerprinting possibilities. The To import scripts into worker global scope, given a
If worker global scope's type is " Let settings object be the current settings object. If urls is empty, return. Parse each value in urls relative to
settings object. If any fail, throw a " Fetch a classic worker-imported script given url and
settings object, passing along performFetch if provided. If this
succeeds, let script be the result. Otherwise, rethrow the exception. Run the classic script script, with
the rethrow errors argument set to true. script will run until it either returns, fails to parse, fails to
catch an exception, or gets prematurely aborted
by the terminate a worker algorithm defined above. If an exception was thrown or if the script was prematurely aborted, then abort all these steps, letting the exception or
aborting continue to be processed by the calling script. Service Workers is an example of a specification that runs this
algorithm with its own perform the fetch
hook. [SW] Support in all current engines. The Support in all current engines. Support in all current engines. A Support in all current engines. The Support in all current engines. The Support in all current engines. The Support in all current engines. The Let url be this's If url's host is null, return the empty
string. If url's port is null, return
url's host, serialized. Return url's host, serialized, followed by " Support in all current engines. The Let host be this's If host is null, return the empty string. Return host, serialized. Support in all current engines. The Let port be this's If port is null, return the empty string. Return port, serialized. Support in all current engines. The Support in all current engines. The Let query be this's If query is either null or the empty string, return the empty string. Return " Support in all current engines. The Let fragment be this's If fragment is either null or the empty string, return the empty string. Return "postMessage()
method. Structured data can be sent over this
communication channel. To send
worker
onmessage
event handler IDL attribute is used.onmessage
method.
data
attribute.postMessage()
. It supports the
structured data in the same manner.postMessage
10.1.3.3 Shared workers
Opera10.6+Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android33+Safari iOS16+Chrome AndroidNoWebView Android?Samsung Internet4.0–5.0Opera Android11–14SharedWorker()
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.MessagePort
objects. The
object returned by the SharedWorker()
constructor holds a
reference to the port on its port
attribute.worker
connect
event. The port for the new client is
given by the event object's source
attribute.onconnect
10.2 Infrastructure
10.2.1 The global scope
10.2.1.1 The
WorkerGlobalScope
common interface
Opera10.6+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android11+[
WorkerGlobalScope
serves as the base class for specific types of worker global
scope objects, including DedicatedWorkerGlobalScope
,
SharedWorkerGlobalScope
, and ServiceWorkerGlobalScope
.WorkerGlobalScope
object has an associated owner set (a
set of Document
and WorkerGlobalScope
objects). It is
initially empty and populated when the worker is created or obtained.SharedWorkerGlobalScope
objects.WorkerGlobalScope
object has an associated type ("classic
" or "module
"). It is set during creation.WorkerGlobalScope
object has an associated url (null or a URL). It is initially
null.WorkerGlobalScope
object has an associated name (a string). It is set during creation.WorkerGlobalScope
. For
DedicatedWorkerGlobalScope
instances, it is simply a developer-supplied name, useful
mostly for debugging purposes. For SharedWorkerGlobalScope
instances, it allows
obtaining a reference to a common shared worker via the SharedWorker()
constructor. For
ServiceWorkerGlobalScope
objects, it doesn't make sense (and as such isn't exposed
through the JavaScript API at all).WorkerGlobalScope
object has an associated policy container (a policy
container). It is initially a new policy container.WorkerGlobalScope
object has an associated embedder policy (an embedder
policy).WorkerGlobalScope
object has an associated module map. It is a module map,
initially empty.WorkerGlobalScope
object has an associated cross-origin isolated
capability boolean. It is initially false.workerGlobal.self
Opera11.5+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android34+Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android?workerGlobal.location
Opera11.5+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android?WorkerLocation
object.workerGlobal.navigator
Opera11.5+Edge79+
Edge (Legacy)17+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android?WorkerNavigator
object.workerGlobal.importScripts(...urls)
Opera10.6+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android11+self
attribute must return the
WorkerGlobalScope
object itself.location
attribute must return the
WorkerLocation
object whose associated WorkerGlobalScope
object is
the WorkerGlobalScope
object.WorkerLocation
object is created after the
WorkerGlobalScope
object, this is not problematic as it cannot be observed from
script.
WorkerGlobalScope
interface:Event handler Event handler event type
onerror
Opera11.5+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android? error
onlanguagechange
Opera11.5+Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS5+Chrome Android?WebView Android37+Samsung Internet?Opera Android? languagechange
onoffline
Opera?EdgeNo
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android? offline
ononline
Opera?EdgeNo
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android? online
onrejectionhandled
rejectionhandled
onunhandledrejection
unhandledrejection
10.2.1.2 Dedicated workers and the
DedicatedWorkerGlobalScope
interface
Opera10.6+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android11+[
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.DedicatedWorkerGlobalScope
object.dedicatedWorkerGlobal.name
Opera?Edge79+
Edge (Legacy)18Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?Worker
constructor. Primarily useful for debugging.dedicatedWorkerGlobal.postMessage(message [, transfer ])
Opera10.6+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android11+dedicatedWorkerGlobal.postMessage(message [, { transfer } ])
Worker
object associated
with dedicatedWorkerGlobal. transfer can be passed as a list of objects
that are to be transferred rather than cloned.dedicatedWorkerGlobal.close()
Opera10.6+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android11+name
getter steps are to return
this's name. Its value
represents the name given to the worker using the Worker
constructor, used primarily
for debugging purposes.postMessage(message,
transfer)
and postMessage(message,
options)
methods on DedicatedWorkerGlobalScope
objects act as
if, when invoked, it immediately invoked the respective postMessage(message, transfer)
and postMessage(message,
options)
on the port, with the same arguments, and returned the same return
value.close()
method steps are to
close a worker given this.
DedicatedWorkerGlobalScope
interface:Event handler Event handler event type
onmessage
Opera10.6+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android37+Samsung Internet?Opera Android11.5+ message
onmessageerror
Opera?Edge79+
Edge (Legacy)18Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android47+ messageerror
10.2.1.3 Shared workers and the
SharedWorkerGlobalScope
interface
Opera10.6+Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS16+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+[
SharedWorkerGlobalScope
object has an associated constructor origin, constructor
url, and credentials. They are initialized when
the SharedWorkerGlobalScope
object is created, in the run a worker
algorithm.connect
events on their SharedWorkerGlobalScope
object for each
connection.sharedWorkerGlobal.name
Opera10.6+Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS16+Chrome Android?WebView Android?Samsung Internet?Opera Android11+SharedWorker
constructor. Multiple SharedWorker
objects can correspond
to the same shared worker (and SharedWorkerGlobalScope
), by reusing the same
name.sharedWorkerGlobal.close()
Opera10.6+Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS16+Chrome Android?WebView Android?Samsung Internet?Opera Android11+name
getter steps are to return
this's name. Its value
represents the name that can be used to obtain a reference to the worker using the
SharedWorker
constructor.close()
method steps are to close a
worker given this.
SharedWorkerGlobalScope
interface:Event handler Event handler event type
onconnect
Opera10.6+Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS16+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+ connect
10.2.2 The event loop
WorkerGlobalScope
object has a closing flag, which must be initially
false, but which can get set to true by the algorithms in the processing model
section below.WorkerGlobalScope
's closing flag is set to true, the event
loop's task queues must discard any
further tasks that would be added to them (tasks already on the
queue are unaffected except where otherwise specified). Effectively, once the closing flag is true, timers stop firing,
notifications for all pending background operations are dropped, etc.10.2.3 The worker's lifetime
Window
s through message channels and their MessagePort
objects.WorkerGlobalScope
object 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.WorkerGlobalScope
object (i.e., if we are creating a nested dedicated worker), then the relevant owner is that
global object. Otherwise, o's global
object is a Window
object, and the relevant owner is that
Window
's associated
Document
.
WorkerGlobalScope
's
owner set is not empty or:WorkerGlobalScope
object is a SharedWorkerGlobalScope
object
(i.e., the worker is a shared worker), andDocument
objects that are fully active or
active needed workers.WorkerGlobalScope
is actually a SharedWorkerGlobalScope
object (i.e., the worker is a shared
worker).10.2.4 Processing model
Worker
or
SharedWorker
object worker, URL url,
environment settings object outside settings, MessagePort
outside port, and a WorkerOptions
dictionary options, it must
run the following steps.SharedWorker
object, and false otherwise.WorkerGlobalScope
object (i.e., we are creating a
nested dedicated worker), then set parent worker global scope to
owner.SharedWorkerGlobalScope
object. Otherwise, create a new
DedicatedWorkerGlobalScope
object.DedicatedWorkerGlobalScope
or
SharedWorkerGlobalScope
object created in the previous step.name
member.type
member.credentials
member.
sharedworker
" if is
shared is true, and "worker
" otherwise.type
member:classic
"module
"credentials
member of options, inside settings, and with onComplete and
performFetch as defined below.Blocked
" when executed upon worker global scope, set
response to a network error. [CSP]logical
" or "concrete
". The one chosen is
implementation-defined.concrete
".data
", then set
worker global scope's cross-origin isolated
capability to false.data:
URL workers in particular (which are
cross-origin from their owner), will be treated in the context of permissions policies. See
w3c/webappsec-permissions-policy
issue #207 for more details.error
at worker.MessagePort
object in
inside settings's realm.WorkerLocation
object and associate it with worker global
scope.connect
at worker global scope, using
MessageEvent
, with the data
attribute
initialized to the empty string, the ports
attribute
initialized to a new frozen array containing inside port, and the source
attribute initialized to inside
port.ServiceWorkerContainer
object whose associated service worker client is
worker global scope's relevant settings object.
WorkerGlobalScope
object's closing flag to true.WorkerGlobalScope
object's relevant agent's event loop's task
queues, discard them without processing them.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.10.2.5 Runtime script errors
WorkerGlobalScope
object as the target.error
at the Worker
object
associated with the worker, using ErrorEvent
, with the message
, filename
, lineno
, and colno
attributes initialized appropriately, and the error
attribute initialized to null.Worker
object is in, thus
repeating the entire runtime script error reporting process one level up.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.Document
, even if some of the
workers along this chain have been terminated and garbage collected.10.2.6 Creating workers
10.2.6.1 The
AbstractWorker
mixinAbstractWorker
interface:Event handler Event handler event type
onerror
Opera?Edge79+
Edge (Legacy)17+Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
Opera10.6+Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android33+Safari iOS16+Chrome AndroidNoWebView Android?Samsung Internet4.0–5.0Opera Android11–14
Opera10.6+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android11+ error
10.2.6.2 Script settings for workers
data
", and inherited
origin otherwise.DedicatedWorkerGlobalScope
object,
then set settings object's top-level origin to outside
settings's top-level origin.10.2.6.3 Dedicated workers and the
Worker
interface
Opera10.6+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android11+[
worker = new Worker(scriptURL [, options ])
Opera10.6+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android11+Worker
object. scriptURL will be fetched and
executed in the background, creating a new global environment for which worker
represents the communication channel. options can be used to define the name of that global environment via the name
option, primarily for debugging purposes. It can also ensure this new
global environment supports JavaScript modules (specify type: "module"
),
and if that is specified, can also be used to specify how scriptURL is fetched through
the credentials
option.worker.terminate()
Opera10.6+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android11+worker.postMessage(message [, transfer ])
Opera10.6+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android11+worker.postMessage(message [, { transfer } ])
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.Worker
object.postMessage(message, transfer)
and postMessage(message,
options)
methods on Worker
objects act as if, when invoked,
they immediately invoked the respective postMessage(message, transfer)
and postMessage(message,
options)
on the port, with the same arguments, and returned the same return
value.postMessage()
method's first argument can be structured data:worker
Worker
interface:Event handler Event handler event type
onmessage
message
onmessageerror
messageerror
Worker(scriptURL,
options)
constructor is invoked, the user agent must run the following
steps:SecurityError
"
SyntaxError
" Let worker URL be the resulting URL record.
blob:
URLs) can be used. data:
URLs can also be used, but they create a worker with an opaque origin.Worker
object.MessagePort
in outside
settings's realm.10.2.6.4 Shared workers and the
SharedWorker
interface
Opera10.6+Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android33+Safari iOS16+Chrome AndroidNoWebView Android?Samsung Internet4.0–5.0Opera Android11–14[
sharedWorker = new SharedWorker(scriptURL [, name ])
Opera10.6+Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android33+Safari iOS16+Chrome AndroidNoWebView Android?Samsung Internet4.0–5.0Opera Android11–14SharedWorker
object. scriptURL will be fetched and
executed in the background, creating a new global environment for which sharedWorker
represents the communication channel. name can be used to define the name of that global environment.sharedWorker = new SharedWorker(scriptURL [, options ])
SharedWorker
object. scriptURL will be fetched and
executed in the background, creating a new global environment for which sharedWorker
represents the communication channel. options can be used to define the name of that global environment via the name
option. It can also ensure this new global environment supports JavaScript
modules (specify type: "module"
), and if that is specified, can also be
used to specify how scriptURL is fetched through the credentials
option. Note that attempting to construct a shared worker with
options whose type
or credentials
values
mismatch an existing shared worker will cause the returned sharedWorker to fire an
error event and not connect to the existing shared worker.sharedWorker.port
Opera10.6+Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android33+Safari iOS16+Chrome AndroidNoWebView Android?Samsung Internet4.0–5.0Opera Android11–14MessagePort
object which can be used to
communicate with the global environment.port
attribute must return the value it was assigned by the object's constructor. It represents the
MessagePort
for communicating with the shared worker.SharedWorker(scriptURL, options)
constructor is invoked:SecurityError
" options to a new
WorkerOptions
dictionary whose name
member is set to the value of options and whose other members
are set to their default values.SyntaxError
" Otherwise, let urlRecord be the resulting URL record.
blob:
URLs) can be used. data:
URLs can also be used, but they create a worker with an opaque origin.SharedWorker
object.MessagePort
in outside
settings's realm.port
attribute of worker.SharedWorkerGlobalScope
objects:name
memberdata:
URLs create a worker with an opaque origin. Both the constructor origin and
constructor url are
compared so the same data:
URL can be used within an
origin to get to the same SharedWorkerGlobalScope
object, but cannot
be used to bypass the same origin restriction.error
and abort these steps.error
at worker and abort these steps.
[SECURE-CONTEXTS]MessagePort
in
settings object's realm.connect
at worker global scope,
using MessageEvent
, with the data
attribute initialized to the empty string, the ports
attribute initialized to a new frozen
array containing only inside port, and the source
attribute initialized to inside
port.10.2.7 Concurrent hardware capabilities
self.navigator.hardwareConcurrency
Opera?Edge79+
Edge (Legacy)15+Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
Opera?Edge79+
Edge (Legacy)15+Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
The
navigator.hardwareConcurrency
attribute's
getter must return a number between 1 and the number of logical processors potentially available
to the user agent. If this cannot be determined, the getter must return 1.10.3 APIs available to workers
10.3.1 Importing scripts and libraries
importScripts(...urls)
method steps are to import scripts into worker global scope given this
and urls.WorkerGlobalScope
object worker global scope, a list of
scalar value strings urls, and an optional
perform the fetch hook
performFetch:module
", throw a
TypeError
exception.SyntaxError
"
For each url in the resulting URL
records:
10.3.2 The
WorkerNavigator
interface
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+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):[
10.3.3 The
WorkerLocation
interface
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+
Opera15+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android37+Samsung Internet?Opera Android14+[
WorkerLocation
object has an associated WorkerGlobalScope
object (a
WorkerGlobalScope
object).
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+href
getter steps are to return this's
WorkerGlobalScope
object's url, serialized.
Opera?Edge79+
Edge (Legacy)14+Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?origin
getter steps are to return the serialization of this's WorkerGlobalScope
object's
url's origin.
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+protocol
getter steps are to return
this's WorkerGlobalScope
object's
url's scheme, followed by ":
".
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+host
getter steps are:WorkerGlobalScope
object's
url.:
" and url's port, serialized.
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+hostname
getter steps are:WorkerGlobalScope
object's
url's host.
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+port
getter steps are:WorkerGlobalScope
object's
url's port.
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+pathname
getter steps are to return the result
of URL path serializing this's WorkerGlobalScope
object's
url.
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+search
getter steps are:WorkerGlobalScope
object's
url's query.?
", followed by query.
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+hash
getter steps are:WorkerGlobalScope
object's
url's fragment.#
", followed by fragment.