LanguagesGet To Work! Multi-Threaded Magic With Web Workers

Get To Work! Multi-Threaded Magic With Web Workers

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Multi-threading in web browsers in the past consisted of creative uses of setTimeout or setInterval. Although this approach worked for some functions, it does not have good handling for inter-thread communications or the ability to really process heavy workloads. Using this method would result in the browser occasionally popping a dialog box telling the user that a script on this page is making things run slowly and giving the user the option to terminate your script.

Web workers add real multi-threading to the web browser including inter-thread communication and the ability to perform heavy lifting without scaring the user into cancelling your script. Web workers are an essential part of any application that needs to be responsive and still be able to do the kinds of heavy lifting common to sophisticated web applications.

Compatibility

Firefox and Chrome have both supported web workers for some time. Internet Explorer 10, released with Windows 8, adds support for web workers. Unfortunately since Microsoft does not intend to releas Internet Explorer 10 on older versions of Windows, Internet Explorer users on Windows 7 and older are excluded from this functionality.

As a result, I would only recommend using web workers if you are working on an installed HTML5 app or in another scenario where you can be sure that your users are using Chrome or Firefox. If you need multi-threading on the open web where you can’t control the web browser you will need to utilize fallback techniques involving setTimeout that are less than perfect.

Workers receive messages from the main page through the onmessage event and publish out messages to the main page through an onmessage event. Because the onmessage event is handled asynchronously you can put long running statements inside of it and have it behave as expected.

The onmessage event has a parameter called “data” that contains the object that was passed in which can be a simple string or a full JavaScript object as long as it is serializable into and out of JSON. This means what you can pass is essentially a data structure without functions.

In the simplest scenario, you can declare a web worker inline by using the blob object, which takes an array of strings to turn into.

The Blob object defines immutable raw data, which is used by several of the newer browser functions including web workers that need a way of working on potentially sizable chunks of data. In the case of declaring an inline web worker, you pass a single element array containing the string of the code you want to run inside of the worker process.

Once your code is in a blob, you can create an object URL from it, which is like an HTML5 equivalent of a file pointer. This object URL is passed to the Worker object that wires up all of the threading functionality to your code.

Next, you need to subscribe to your worker’s onmessage event so you can get messages back from your web worker. In the example below, the onmessage event just pops an alert box containing the data returned from the worker. Finally, we post a single message to the worker to get it started.

var URLObject = window.webkitURL?window.webkitURL:window.URL;
 var blob = new Blob(["self.onmessage = function(e) { "+
"self.postMessage('Hello:'+ e.data.Name); }"]);
var worker = new Worker(URLObject.createObjectURL(blob));
 worker.onmessage = function(e) {
  alert("Got:"+ e.data);
 };
 worker.postMessage({Name:"David"})

A More Legible Approach

The basic approach of passing a string to a Blob to turn into a web worker can be upgraded into a far more legible form of declaring your web worker code inside of a separate script tag with a type of “javascript/worker” that you can then copy the text of into a blob to run. Scripts with the type of “javascript/worker” will not be inline executed the way a “text/javascript” script normally would.

<script
id="InlineWorker" type="javascript/worker">
self.onmessage = function(e) {
self.postMessage('Hello:'+ e.data.Name); }
</script>
<script type="text/javascript">
var URLObject = window.webkitURL?window.webkitURL:window.URL;
var blob = new
Blob([document.getElementById("InlineWorker").textContent]);
var worker = new Worker(URLObject.createObjectURL(blob));
worker.onmessage = function(e) {
 alert("Got:"+ e.data);
};
worker.postMessage({Name:"David"})
</script>

Technically you could put your web worker code inside of a hidden div and copy it in using this approach but using the codified javascript/worker syntax is a service to the legibility of your application to all of the developers that come after you.

Creating a Web Worker From an External File

If you are developing a non-trivial application, I would highly recommend putting your web worker in an external file. If you do this, you will need to test your application on an actual web server and not just browse to it on your local disk or you will get “SECURITY_ERR: DOM Exception 18”, which is Chrome’s gentle way of telling you that it’s not sure this .js file is from the same server that served up the HTML file so it doesn’t trust it enough to let it run as a web worker.

Creating a web worker from an external file doesn’t need the BLOB or createObjectURL. You simply pass in the filename of your external .js file that defines the web worker and the browser will take care of the rest.

<script language="JavaScript">
var worker = new Worker("webworker.js");
worker.addEventListener('message', function(e) {
$("UL").append("<li>"+ e.data +"</li>");
}, false);
function RunWorkerNow(event)
{
worker.postMessage({Command:'start',
GoNumber:document.getElementById("TheNumber").value});
}
</script>

Error Handling

Web workers are running asynchronously and can encounter errors outside of a try/catch block on your main page. For this reason, to handle errors with web workers you will need to add an event handler to the on error event.

worker.addEventListener('error', function(e) {
alert("Error:"+ e.message);
}, false);

Conclusion

Web workers provide an exciting new way of multi-threaded programming in a browser, opening up exciting new possibilities for sophisticated processing-intensive web applications.

About the Author:

David Talbot has over 14 years of experience in the software industry with experience ranging from license plate recognition using neural networks to television set-top boxes to highly scalable web applications. His main focus is building rich user interface web applications on the .NET platform. He is also the author of Applied ADO.NET and numerous articles on technology.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories