Update: I have summarised this series of blog posts in a CodeProject article, available here.

In this series of posts I showed a sweet way to use Web Workers to improve performance on browsers that support them, without impacting performance on browsers that don't, by using jQuery 1.5 Deferred objects to wrap a "generic" worker.

jQuery Plugin

Click here for the jQuery plugin page where you can download the jQuery plugin code and report bugs. Both the compressed and uncompressed version are available, whether you want to see the final code or just want to include it in your application.

Usage

To use this plugin optimally, you should isolate functions in your code that meet the following criteria:

  1. The function must be "static" - it cannot access any closure variables, only variables that are passed to it through its arguments. You can use setTimeout, setInterval, XMLHttpRequest, and construct Web Workers - but no other globals are available.
  2. The function takes longer than 100ms to run. This ensures that the benefits of running it in a background worker are greater than the overhead of constructing the worker.
  3. The function executes less than 5 million statements. This is the limit after which Internet Explorer will display the error "A script on this page is causing Internet Explorer to run slowly". This occurs because IE does not support Web Workers and the code is run in the UI thread. To get around this, split the work into multiple parts, implant calls to setTimeout into it, or offer an alternate application to IE users. Of course, if you are optimising an existing application, your code won't run any slower in Internet Explorer than it does already.

To get started, download the minified file and include it in your application after you've included jQuery 1.5.

Basic Use

Call the $.work function to run a function in another thread. This returns a Deferred object which you can use like any other Deferred jQuery object.

Let's assume you've got a long running function "doStuff" in your application:

	function doStuff(arg1, arg2) {
		//Do lots of stuff with arg1 and arg2
	}
	
	var result = doSomething("a", "b");
	//do something with the result

This can be parallelised by re-jigging the function to take a single parameter, and adding a callback to the 'done' helper function:

	function doStuff(args) {
		//Do lots of stuff with args.arg1 and args.arg2
	}
	
	$.work(doStuff, {a:1, b:100}).done(function(result){
		//do something with the result
	});

Handling errors

The 'done' function above only gets called when the function executes without any exceptions. To handle exceptions, use the 'then' and 'fail' helper functions:

	function doStuff(args) {
		//Do lots of stuff with args.arg1 and args.arg2
	}
	
	$.work(doStuff, {a:1, b:100}).then(function(result){
		//do something with the result
	}).fail(function(event){
		//exception occurred! look at the event argument.
	});

Multiple threads (fork and join)

You can run multiple workers and easily join the results using the $.when Deferred helper function:

	function doStuff(args) {
		//Do lots of stuff with args.arg1 and args.arg2
	}
	
	//Split your work into multiple workers (fork)
	var work1 = $.work(doStuff, {a:1, b:50});
	var work2 = $.work(doStuff, {a:51, b:100});
	
	//Use $.when to be notified when they're all complete (join)
	$.when(work1, work2).then(function(result1, result2){
		//success - do something with result1 and result2
	}).fail(function(event){
		//exception occurred! look at the event argument.
	});

I look forward to seeing some great applications of this plugin!