Web Workers allow running scripts in the background without blocking or freezing the user interface. By using Web Workers to run non-UI scripts in the background, your application can take advantage of multiple cores on your machine to execute scripts concurrently.
Workers allows you to spawn background workers running scripts in parallel to your main page. This allows for thread-like operation with message-passing as the coordination mechanism. Web Workers are also described as “Workers”.
This means that a long running computation no longer needs to block your user interface. HTML5 Web Workers typically run on separate threads so you can take advantage of multicore CPUs.
Although a lot of focus in the specification is around, the architecture and code can be used on the server side too. The node-webworker module aims to implement as much of the HTML5 Web Workers API as is practical and useful in the context of NodeJS.
Web Worker Scenarios
You will want to consider Web Workers:
* Encoding/decoding a large string that you create on the client and wish to keep it there.
* Code syntax highlighting or other real-time text analysis (like spell checking).
* Background I/O (e.g. Polling web services).
* Complex mathematical calculations (prime numbers, encryption, simulated annealing, etc.) – think on a web app that work offline and still need to run…
* Analyzing or processing video or audio data (including face and voice recognition)
- Image processing by using the data extracted from the <canvas> or the <video> elements. You can divide the image into several zones and push them to the different Workers that will work in parallel. You’ll then benefit from the new generation of multi-cores CPUs. The more you have, the faster you’ll go.
- big amount of data retrieved that you need to parse after an XMLHTTPRequest call. If the time needed to process this data is important, you’d better do it in background inside a Web Worker to avoid freezing the UI Thread. You’ll then keep a reactive application.
- concurrent requests against a local database. IndexDB will allow what the Local Storage can’t offer us: a thread-safe storage environment for our Web Workers.
Workers are relatively heavy-weight, and are not intended to be used in large numbers. Generally, workers are expected to be long-lived, have a high start-up performance cost, and a high per-instance memory cost.
Workers do not have access to the direct access to the Web page or the DOM API. Although they do not block the UI, they do use CPU cycles and can make the system be less responsive.
Workers are not supported in every browser. The latest versions of browsers (IE 10, Firefox 16 and later, Chrome 23 and later, Safari 5.1 and later, Opera 12.1 and later, and others) and Windows 8 applications are supported.
See CanIUse site for supported browsers.
Support through a polyfill (emulation) does not really make sense. For backward compatibility, you can just call your code inline with the down-side being that you will block the UI thread. Or you can mimic ‘concurrency’ by using techniques like
XMLHttpRequest, and event handlers. Although these features run asynchronously, non-blocking doesn’t necessarily mean concurrency. Asynchronous events are processed after the current executing script has yielded.
Check for Support for Workers
You can check to see if Workers are supported in your browser. A call to typeof(Worker) will return the global Worker property. The property will be undefined if your browser does not support Workers.
Using Web Workers
Let’s start with a simple example. Let’s count from 0 to 10 million by ten-thousands.
The main page looks like this:
And in counter.js:
In this example, the page updates a counter until it reaches 10,000,000.
In lieu of counting, you can imagine retrieving or updating data on a Web service.
Creating Web Workers
You can spawn background scripts that run in parallel with the main page. A new worker object requires a .js file, which is included via an asynchronous request to the server.
The code sets up event listeners and communicates with the script that spawned it.
Communicating with Web Workers
In the context of a worker, both
this reference the global scope for the worker.
- The window object
- The document object
- The parent object
All communication to and from the worker thread is managed through messages. Both the host worker and the worker script can send messages by using postMessage and listen for a response by using the onmessage event. The content of the message is sent as the data property of the event.
Or you can use addEventListener.
Then inside the Worker, in the case of the example in aWorkerTask.js, use postMessage to send a message back to the originating thread.
You can also post serialized data or JSON.
Stopping Web Worker
To terminate a web worker, and free browser/computer resources, use the terminate() method:
You will want to handle any errors that are thrown in your web workers. If an error occurs while a worker is executing, an
You get three useful properties for figuring out what went wrong:
filename – the name of the worker script that caused the error,
lineno – the line number where the error occurred, and
message – a meaningful description of the error.
Initializing Worker, Two-way Communication
Messages passed between the main page and workers are copied, not shared. For example, you can pass a parameter inside JSON that is accessible in both locations. It appears that the object is being passed directly to the worker even though it’s running in a separate, dedicated thread.
The object is being serialized as it’s handed to the worker, and then, de-serialized on the other end. The page and worker do not share the same instance, so the end result is a duplicate created on each pass. Most browsers implement this feature by automatically JSON encoding/decoding the value on either end.
To set up two-way communication, both the main page and the worker thread listen for the onmessage event.
For example, when a button is pressed, a message is sent to the Worker that then echos it back. The message is passed in using JSON and then back from the Worker as JSON too.
Here is the HTML.
The following example tries to calculate Pi. Here’s the html:
Here is the worker.
More Web Worker Features
There are additional ways to use Web Workers. Let your creativity begin.
You may want to create the Worker inline inside the web page instead of inside a separate file. Or you have may a need to provide the code by some external source as a string. In these cases you can use inline Web Workers.
Here is an example script tag.
For more information, see Working with Inline Web Workers.
Shared web workers allow any number of scripts to communicate with a single worker.
ShareWorkers not supported in all modern browsers.
Workers may spawn more workers if they wish. So-called subworkers must be hosted within the same origin as the parent page. Also, the URIs for subworkers are resolved relative to the parent worker’s location rather than that of the owning page. This makes it easier for workers to keep track of where their dependencies are.
Subworkers are not currently supported in all browsers.
Worker threads have access to a global function,
importScripts() , which lets them import scripts or libraries into their scope. It accepts as parameters zero or more URIs to resources to import, such as:
Mozilla developer page shows Advanced passing JSON Data and creating a switching system. The demos shows how you can pass some complex data and have to call many different functions both in the main page and in the Worker
Sample code is provided in the Web Worker specification for these scenarios:
- A background number-crunching worker. The simplest use of workers is for performing a computationally expensive task without interrupting the user interface.
- Worker used for background I/O. The main document uses two workers, one for fetching stock updates for at regular intervals, and one for fetching performing search queries that the user requests.
- Shared workers introduction. Shared workers use slightly different APIs, since each worker can have multiple connections.
- Shared state using a shared worker. Multiple windows (viewers) can be opened that are all viewing the same map.
- Delegation. A computationally expensive task that is to be performed for every number from 1 to 10,000,000 is farmed out to ten subworkers.
IE10 offers you to directly debug the code of your Web Workers inside its script debugger like any other script.
For that, you need to launch the development bar via the F12 key and navigate to the “Script” tab. You shouldn’t see the JS file associated to your worker yet. But right after pressing the “Start debugging” button, it should magically be displayed:
For more information about Web Workers, see:
- Web Workers specification at W3C
- Using web workers from Mozilla Developer Network
- Web Workers rise up from Dev.Opera
- Web Workers (Windows) on MSDN
- Design of Web Workers for NodeJS
- The Basics of Web Workers from HTML5 Rocks Tutorials
- Debugging Web Workers in IE10
Sample code is available in the DevDays GitHub repository. See https://github.com/devdays/html5-tutorials