Tech and Media Labs
This site uses cookies to improve the user experience.




HTML5 Web Workers

Jakob Jenkov
Last update: 2014-08-08

The Web Workers API makes it possible to execute a JavaScript file asynchronously and autonomously. A web worker is essentially a thread executing a JavaScript file. Thus, using web workers you can achieve multi threading in your web applications.

Creating a Web Worker

You create a web worker like this:

var worker = new Worker("http://jenkov.com/worker.js");

The string passed as parameter to the Worker() is the URL of the JavaScript file to execute.

Communicating With the Web Worker

You communicate with the web worker using the HTML5 Messaging API, by posting messages to, and receiving messages from, the web worker. Here is an example:

var worker = new Worker("http://jenkov.com/worker.js");

worker.onmessage = function(event) {
    alert("Reply: " + event.data);
}

worker.postMessage("Hello worker!");

First a Worker is created.

Second, an onmessage event listener function is set on the web worker. This function is called when the worker sends messages back to the page that created it.

Third, a message is sent to the web worker using the worker.postMessage() function.

The web worker can respond like this:

this.onmessage = function(event) {
    postMessage("Reply from web worker");
}

This code is part of the JavaScript file executed by the web worker. The this keyword is a reference to the web worker instance itself. An onmessage event listener function is added to the web worker. This is not the same onmessage listener as the page creating the web worker added, even if both were added on the worker instance. The web worker responds to the message using the postMessage().

Exchanging JSON

In the first implementations of web workers the browsers only allowed strings to be exchanged as messages. You can encode a JSON object using the JSON.stringify() function and decode it again using the JSON.parse() function.

However, recent implementations allow for exchange of values or JSON objects that can be handled by the structured clone algorithm.

Web Worker Implementation

Here is a full implementation of a web worker:

this.onmessage = function(event) {

    postMessage("Reply from web worker");

}

//Implementation of web worker thread code
setInterval(function() { runEveryXSeconds() }, 5000);

function runEveryXSeconds() {
    postMessage("Calling back at : " + new Date().getTime());
}

This web worker implementation listens for messages, as well as sends a message every 5 seconds to the page that started it.

Web Worker Live Example

Here you can execute the example code shown earlier. Click the button below to execute the example.

To stop the messages sent back every 5 seconds, hit refresh in the browser.

The Web Worker Sandbox

The web workers run in a kind of sandbox, meaning that the web worker has limited access to the features JavaScript normally has access to when executed in a browser.

A web worker does not have access to the DOM of the page that creates the web worker.

Here is a list of what a web worker can do inside the web worker JavaScript:

  • Listen for messages, using the onmessage event listener function.
  • Send messages via the postMessage() function.
  • Send AJAX requests using the XMLHttpRequest.
  • Create timers using the setTimeout() and sendInterval() functions.
  • Web Sockets
  • Web SQL Databases
  • Web Workers
  • Import more scripts using importScripts()

Importing JavaScript in a Web Worker

You can import JavaScript files for use in your web worker, using the importScripts() function. This is a special function available in a web worker. Here is an example:

importScripts("myscript.js");
importScripts("script1.js", "script2.js");

You can load one or more scripts using the importScripts() function, as you can see from the example above. The scripts are loaded synchronously, and executed one at a time.

SharedWorker

An ordinary web worker is only accessible by the page that created it. If you want to share a web worker between multiple pages, you can use a SharedWorker. A SharedWorker is accessible by all pages that are loaded from the same origin (domain).

Creating a SharedWorker

You create a SharedWorker like this:

var worker = new SharedWorker("shared-worker.js");

The string passed as parameter to the SharedWorker constructor is the URL of the JavaScript the SharedWorker is going to execute.

All pages that create an instance of a SharedWorker with the same URL passed as parameter, will essentially get a connection to the same SharedWorker behind the scenes.

Connecting to a SharedWorker

A SharedWorker has a concept called ports through which the various pages that reference the SharedWorker can communicate with it. The API is again similar to the HTML5 Messaging API.

Here is an example of how to add a message listener to the port of a SharedWorker:

var worker = new SharedWorker("/html5/web-worker-shared.jsp");

worker.port.addEventListener("message",
        function(event) {
            alert(event.data);
        }
        , false
);

worker.port.start();

First at SharedWorker is created. Second, a message event listener function is added to the SharedWorker's port. Third, the port is started. If you do not start the port, you cannot send messages to the SharedWorker.

Sending Messages to a SharedWorker

Once the port is started and your page is listening for messages on the port, you can send messages to the SharedWorker using the port.postMessage() function. Here is an example:

worker.port.postMessage("First Message");

SharedWorker Implementation

A SharedWorker, like an ordinary web worker, needs an implementation in a JavaScript file. Here is an example implementation:

var ports = [] ;

onconnect = function(event) {

    var port = event.ports[0];
    ports.push(port);
    port.start();

    port.addEventListener("message",
        function(event) { listenForMessage(event, port); } );
}


listenForMessage = function (event, port) {
    port.postMessage("Reply from SharedWorker to: " + event.data);
}

//Implementation of shared worker thread code
setInterval(function() { runEveryXSeconds() }, 5000);

function runEveryXSeconds() {
    for(i = 0; i < ports.length; i++) {
        ports[i].postMessage("Calling back at : "
                + new Date().getTime());
    }
}

This implementation first creates an array for storing the ports of all the pages that connects with the SharedWorker.

Second, an onconnect function is defined. This function is called when a page connects to the SharedWorker.

The onconnect function first obtains the port to the connecting page, stores it in the port array and then starts the port. If you do not start the port, you cannot receive messages from it. Finally the onconnect function adds a message listener function to the port. Notice how a new anonymous function is created for each page connecting. This anonymous function captures the port to the connecting page and passes it as parameter to the listenForMessage() function called from the anonymous function.

After the onconnect function is a definition of the event listening function listenForMessage() This function simply responds to the port from which the message was received with a simple message.

The last part of this SharedWorker contains the implementation of the autonomous behaviour this SharedWorker has. The setInterval() function is called to make the runEveryXSeconds() execute every 5 seconds (5000 milliseconds).

The runEveryXSeconds() simply iterates all the connected ports and write a message to them. A more advanced implementation could connect to a server and fetch data which could be distributed to all the pages connected to the SharedWorker.

SharedWorker Live Example

Here is a live example of a SharedWorker. Start the SharedWorker by clicking the button on the left. Send a message to the SharedWorker by clicking on the button on the right.

Jakob Jenkov




Copyright  Jenkov Aps
Close TOC