Here’s a low tech demo of the power of web workers. A hundred flies will swarm randomly. Ones that get too high get sleepy, ones that sink too low get re-caffeinated and ones that cover the least distance will perish.

Sourcecode is gisted on GitHub

I should start by saying this was not trivial to write. As we will see the web workers API is disarmingly simple but the tripwires are many. The biggest issue is the lack of useful debug support because the global worker object exists in a vacuum.

The basics

Your browser can be serviced by one or more web workers. A worker will perform non-DOM related tasks in a separate thread. This means worker processes are performed asynchronously with respect to the browser (in fact the worker has no access to the browser’s window object, the equivalent global object being self which references the worker). The implications are exciting. Lengthy computational tasks can be undertaken with no effect on browser responsiveness.

A web worker is a .js file which you set as an attribute of a worker object.

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

The browser and the worker speak the same language. Messages are sent and received using postMessage and onMessage respectively

//on the browser worker.onmessage = function(e){ updateThing(e.data); } var invokeWorker = function(action) { worker.postMessage({ 'action': action, 'things': things }); }

//on the worker { //.... updates.maxDy = 2; updates.symbol = '*'; postMessage(updates); } var onmessage = function(e){ things = e.data.things; actions[e.data.action](); }

By these means data and instructions can be passed to and fro between browser and worker.

Data streaming is by value not by reference. The data is serialized in transit and rebuilt as a new but (hopefully) identical object on the other side. In theory any serialize-able non-DOM object can be streamed. Mozilla, Chrome 5 and Safari 5 support posting of complex objects to workers (thanks to Rick Waldron and Charles Lehner for pointing out bugs in my code which webkit browsers objected to)

IE8 has no web worker support.

The app

The crazy flies app makes use of a web worker to analyze and acting upon the latest data pattern (i.e. which flies are where) while the browser focuses on buzzing them around the screen as fast as possible. Each fly is an instance of a Thing object which recursively moves itself around the screen in a random fashion. Every second the browser posts four instructions to the worker:

intervals[0] = window.setInterval(invokeWorker.curry('updatePaths'),1000); intervals[1] = window.setInterval(invokeWorker.curry('makeHighestSleepy'),1000), intervals[2] = window.setInterval(invokeWorker.curry('makeLowestBuzzy'),1000); intervals[3] = window.setInterval(invokeWorker.curry('killSlowest'),1000);

The first instruction updates the approximate total distance traveled by each living Thing. The other three perform further analysis on the state of Things and then send back the appropriate data to the browser so that it can modify the flies.

The web worker does make a difference. Every second it uses Pythagoras’ theorem to increment the net path-length of each fly and every second it is sorting arrays three ways to find the highest lowest and least traveled flies. When I prototyped the app I first had all processes running in the browser. It limped along with a lengthy freeze every second. In contrast, with a web worker employed the scene plays out seamlessly on my computer (though the fluency may vary based on your processing speed).

Conclusion

JavaScript web workers are in their infancy and the use cases are limited (top of my wish-list is worker partitioning of the browser itself so that DOM events could run in separate threads). Browser support varies from patchy to non-existent and debugging is tough. It’s too early to claim web workers as an industrial strength solution but the outlook is promising, and in the meantime they’re fun to mess around with.