Let HTML5 Web Workers Take The Strain


A web worker, as defined by the World Wide Web Consortium (W3C) and the Web Hypertext Application Technology Working Group (WHATWG), is a JavaScript script executed from an HTML page that runs in the background, independently of other, user-interface scripts that may also have been executed from the same HTML page. Web workers are able to utilize multi-core CPUs more effectively

An example application can be found on the demo link at the foot of the page. The code can be found in scripts/webworkers.js. This simple script creates a new Web Worker when the Start button is clicked. This calls startBackgroundProcessingWebWorker(), which creates a new instance of a worker:

// Create the web worker, must be in a seperate file
worker = new Worker( 'scripts/myScripts/ backgroundProcessingWebWorker.js' );
// Listen to messages from the webworker
worker.onmessage = function (event) {
  if (event.data && (event.data + " ").match(/^log:/i)) {
    console.log(event.data.match( /^log:\s*(.*) /)[1]);
  } else {
    document.querySelector( '#backgroundProcessing' ).innerHTML = event.data;
  }
}
// Start the worker
worker.postMessage();

The script that actually runs as a separate thread is 'scripts/backgroundProcessingWebWorker.js' (it just calculates prime numbers – if you ran it as ordinary JavaScript code it would freeze the browser as not responding). We print out to the web page, the messages it sends back to the main JavaScript thread with:

document.querySelector( '#backgroundProcessing' ).innerHTML = event.data;

The Web Workers specification defines an API for spawning background scripts in a web application. Web Workers allow you to run processor-intensive long-running scripts to handle computationally intensive tasks, but without blocking the UI or other scripts to handle user interactions. Workers utilize thread-like message passing to achieve parallelism. 

Web Workers run in an isolated thread. As a result, the code that they execute needs to be contained in a separate file. However, the first thing we do is create a new worker object in the main page. 

The constructor takes the name of the worker script, for example:

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

If the specified file exists, the browser will spawn a new worker thread, which is downloaded asynchronously. The worker will not begin until the file has completely downloaded and executed.  After creating the worker, start it by calling the postMessage() method:

worker.postMessage(); // Start the worker.

Communication between a worker and its parent page is done using an event model and the postMessage() method. Depending on your browser/version, postMessage() can accept either a string or JSON object as its single argument. The latest versions of the modern browsers support passing a JSON object.

Below is a example of using a string to pass 'Hello World' to a worker in doWork.js. The worker simply returns the message that is passed to it.

Main script:

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

worker.addEventListener('message', function(e) {
     console.log('Worker said: ', e.data);
}, false);

worker.postMessage('Hello World'); // Send data to our worker. doWork.js (the worker):

self.addEventListener('message', function(e) {
     self.postMessage(e.data);
}, false);

When postMessage() is called from the main page, our worker handles that message by defining an onmessage handler for the message event. The message payload (in this case 'Hello World') is accessible in Event.data. Although this particular example is not very exciting, it demonstrates that postMessage() is also your means for passing data back to the main thread. 





Published on 24 March 2013 in HTML5 Features