JavaScript Threading With HTML5 Web Workers

Forget transforms, native video, semantic tags and all the other frivolous HTML5 nonsense; web workers are the best features to arrive in browsers since JavaScript! Web workers finally allow developers to run ongoing processes in a separate thread.

Threading sounds complicated and some development languages make it tricky, but you’ll be pleased to hear that JavaScript’s implementation is good and the W3C working draft is stable. Web workers offer huge client-side performance gains, but there are a few things to note before we start…

Web Worker Restrictions

Web workers operate independently of the browser UI thread so they’re not able to access many of the features JavaScript developers know and love. The primary restriction is that web workers have no access to the DOM; they cannot read or modify the HTML document. In addition, you cannot access global variables or JavaScript functions within the page. Finally, access to some objects is restricted, e.g. window.location properties are read-only.

However, web workers can use standard JavaScript data types, handle XMLHttpRequest (Ajax) calls, use timers and even import other workers. They are ideal for time-consuming tasks such as analyzing large blocks of data, game AI logic, ray-tracing, etc.

Web Worker Browser Support

At the time of writing, all the recent editions of Firefox, Chrome, Safari and Opera support web workers to some extent. Guess which browser is missing?

Unsurprisingly, web workers are not implemented in any version of Internet Explorer. Even IE9 does not offer support but I suspect/hope it will be implemented in the final release. Until that time, you have three options:

  • Forget about web workers for another year or two.
  • Accept that your application will break in IE.
  • Implement your own web worker shim which falls back to timer-based pseudo-threading or array processing. That may not be possible or advisable in all applications.

What is a Web Worker?

A web worker is a single JavaScript file loaded and executed in the background. There are two types:

  • Dedicated workers: these are linked to their creator (the script which loaded the worker).
  • Shared workers: the allow any script from the same domain (somesite.com) to communicate with the worker.

Today, we’re looking at dedicated web workers…

Creating a Dedicated Web Worker

To create a dedicated web worker, you pass a JavaScript file name to a new instance of the Worker object:


var worker = new Worker("thread1.js");

Communicating With a Dedicated Web Worker

Since the web worker cannot access the DOM or execute functions within the page’s script, all communication is handled through an event interface. The web page script passes a single data argument via the postMessage() method and receives one back via an onmessage event handler, e.g.

pagescript.js:


var worker = new Worker("thread1.js");

// receive messages from web worker
worker.onmessage = function(e) {
	alert(e.data);
};

// send message to web worker
worker.postMessage("Jennifer");

The web worker script receives and sends data via it’s own onmessage event handler and postMessage() method accordingly:

thread1.js:


self.onmessage = function(e) {
	self.postMessage("Hello " + e.data);
};

The message data can be a string, number, boolean, array, object, null or undefined. Data is always passed by value and serialized then de-serialized during the communication process.

Handling Dedicated Web Worker Errors

Web worker code is unlikely to be perfect, and logic errors could be caused by the data passed by the page script. Fortunately, errors can be caught using an onerror event handler. The handler event is passed an object with 3 properties:

  • filename: the name of the script which caused the error;
  • lineno: the line number where the error occurred; and
  • message: a description of the error.

pagescript.js:


worker.onerror = function(e) {
	alert("Error in file: "+e.filename+"nline: "+e.lineno+"nDescription: "+e.message);
};

Loading Further JavaScript Files

One or more additional JavaScript libraries can be loaded within a web worker using importScripts(), e.g.


importScripts("lib1.js", "lib2.js", "lib3.js");

Alternatively, you could load further web workers … but, I’d recommend keeping it simple until browsers catch up with your threading ambitions!

Stopping a Dedicated Web Worker

The web worker thread can be stopped using the close() method, e.g.

thread1.js:


self.onmessage = function(e) {
	if (e.data == "STOP!") self.close();
};

This discards any tasks awaiting processing and prevents further events being queued.

That’s all you need to know about dedicated web workers. In my next post, we’ll discuss shared web workers — a more complex beast!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments

Comments on this post are closed.