Dedicated Workers are the simplest kind of Workers. Once created, they remain linked to their parent page (the HTML5 page that created them). An implicit "communication channel" is opened between the Workers and the parent page, so that messages can be exchanged.
Let's look at the first example, taken from the W3C specification: "The simplest use of workers is for performing a computationally expensive task without interrupting the user interface. In this example, the main document spawns a worker to (naïvely) compute prime numbers, and progressively displays the most recently found prime number."
This is the example we tried earlier, without Web Workers, and it froze the page. This time, we'll use a Web Worker. Now you will notice that the prime numbers it computes in the background are displayed as soon as the next prime number is found.
Try this example online using CodePen. Note that we cannot run this example on JsBin as Workers need to be defined in a separate JavaScript file.
The HTML5 page code from this example that uses a Web Worker:
<!DOCTYPE HTML>
<html>
<head>
<title>Worker example: One-core computation</title>
</head>
<body>
<p>The highest prime number discovered so far is: <output id="result"></output></p>
<script>
var worker = new Worker('worker.js');
worker.onmessage = function (event) {
document.getElementById('result').textContent = event.data;
};
</script>
</body>
</html>
the Web Worker is created at line 9
its code is in the worker.js file
Lines 10-12 process messages sent asynchronously by the worker
event.data is the message content.
Workers can only communicate with their parent page using messages. See the code of the worker below to see how the message has been sent.
The code of the worker (worker.js):
var n = 1;
search: while (true) {
n += 1;
for (var i = 2; i <= Math.sqrt(n); i += 1)
if (n % i == 0)
continue search;
// found a prime!
postMessage(n);
}
There are a few interesting things to note here:
There is an infinite loop in the code at line 2 (while true...). This is not a problem as it runs in the background.
When a prime number is found, it is posted to the creator of the Web Worker (aka the parent HTML page), using the postMessage(...) function (line 8).
Computing prime numbers using such a weak algorithm is very CPU intensive. However, the Web page is still responsive: you can refresh it and the "script not responding" error dialog box will not appear, etc. There is a demo in the next section of this course chapter in which some graphic animation has been added to this example, and you can verify that the animation is not affected by the computations in the background.
We can improve this example a little by testing whether the browser supports Web Workers, and by displaying some additional messages.
This occurs with Opera, Chrome and Firefox. With Chrome, Safari or Chromium, you can run the browser using some command line options to override these security constraints. Read, for example, this blog post that explains this method in detail.
Ok, back to our improved version! This time, we test if the browser supports Web Workers, and we also use a modified version of the worker.js code for displaying a message and have it wait 3 seconds before starting the computation of prime numbers.
You can download this example: WebWorkersExample1.zip
HTML code:
<!DOCTYPE HTML>
<html>
<head>
<title>Worker example: One-core computation</title>
</head>
<body>
<p>The highest prime number discovered so far is: <output id="result"></output></p>
<script>
if(window.Worker){
// web workers supported by the browser
var worker=new Worker("worker1.js");
worker.onmessage=function(event){
document.getElementById('result').textContent = event.data;
};
}else{
// the browser does not support web workers
alert("Sorry, your browser does not support Web Workers");
}
</script>
</body>
</html>
Line 9 shows how to test if the browser can run JavaScript code that uses the HTML5 Web Workers API.
Here is the worker1.js code:
postMessage("Hey, in 3s, I'll start to compute prime numbers...");
setTimeout(function() {
// The setTimeout is just useful for displaying the message in line 1 for 3 seconds and
// making it visible
var n = 1;
search: while (true) {
n += 1;
for (var i = 2; i <= Math.sqrt(n); i += 1)
if (n % i == 0)
continue search;
// found a prime!
postMessage(n);
}
}, 3000);
In this example, we just added a message that is sent to the "parent page" (line 1) and we use the standard JavaScript method setTimeout() to delay the beginning of the prime number computation by 3s.
So far we have created and used a worker. Now we will see how to kill it!
A worker is a thread, and a thread uses resources. If you no longer need its services, it is best practice to release the used resources, especially since some browsers may run very badly when excessive memory consumption occurs. Even if we unassign the variable that was used to create the worker, the worker itself continues to live - it does not stop! Worse: the worker continues in its task (therefore memory and other resources are still allocated) but it becomes inaccessible. In this situation, we cannot do anything but close the tab/page/browser.
The Web Worker API provides a terminate() method that we can use on any worker, to end its life. After a worker has been killed, it is not possible to undo its termination. The only option is to create a new worker.
HTML code:
<!DOCTYPE HTML>
<html>
<head>
<title>Worker example: One-core computation</title>
</head>
<body>
<p>The highest prime number discovered so far is: <output id="result"></output></p>
<script>
if(window.Worker){
// web workers supported by the browser
var worker=new Worker("worker2.js");
worker.onmessage=function(event){
document.getElementById('result').textContent = event.data;
};
}else{
// the browser does not support web workers
alert("Sorry, your browser does not support Web Workers");
}
setTimeout(function(){
// After 10 seconds, we kill the worker
worker.terminate();
document.body.appendChild(document.createTextNode("Worker killed, 10 seconds elapsed !")
);}, 10000);
</script>
</body>
</html>
Notice at line 22 the call to worker.terminate(), that kills the worker after 10000ms.
worker2.js is the same as in the last example:
postMessage("Hey, in 3s, I'll start to compute prime numbers...");
setTimeout(function() {
// The setTimeout is just useful for displaying the message in line 1 for 3 seconds and
// making it visible
var n = 1;
search: while (true) {
n += 1;
for (var i = 2; i <= Math.sqrt(n); i += 1)
if (n % i == 0)
continue search;
// found a prime!
postMessage(n);
}
}, 3000);
A Web worker can also kill itself by calling the close() method in the worker's JavaScript file:
To sum up, there are 3 different ways to kill a Web Worker:
Close the tab/window of the parent. This will kill all workers that have been created by this parent tab/window.
In the parent's JavaScript file: call the terminate() method on a worker instance. Example: worker.terminate();
Call the close() method in a Worker's JavaScript file. This will kill the current Worker that is running this code.
External scripts can be loaded by workers using the importScripts() function.
worker.js:
importScripts('script1.js');
importScripts('script2.js');
// Other possible syntax
importScripts('script1.js', 'script2.js');
The included scripts must follow the same-origin policy.
The scripts are loaded synchronously and the function importScripts() doesn’t return until all the scripts have been loaded and executed. If an error occurs during a script importing process, a NETWORK_ERROR is thrown by the importScripts function and the code that follows won’t be executed.
Debugging threads may become a nightmare when working on the same object (see the "thread security" section at the beginning of this page). To avoid such a pain, the Web Workers API does several things:
When a message is sent, it is always a copy that is received: no more thread security problems.
Only predefined thread-safe objects are available in workers, this is a subset of those usually available in standard JS scripts.
The navigator object
The location object (read-only)
XMLHttpRequest
setTimeout()/clearTimeout() and setInterval()/clearInterval()
Importing external scripts using the importScripts() method
The DOM (it's not thread-safe)
The window object
The document object
The parent object
WOW! This is a lot! So, please be careful!
This is well illustrated below:
Chrome has already implemented a new way for transferring objects from/to Web Workers by reference, in addition to the standard "by copy" method. This is in the HTML 5.1 draft specification from the W3C - look for "transferable" objects!
The canvas is not usable from Web Workers, however, HTML 5.1 proposes a canvas proxy.
Like other multi-threaded applications, debugging Web Workers can be a tricky task, and having a good tool-kit makes this process much easier.
Chrome provides tools for debugging Web Workers. See Debug Background Services With Chrome DevTools.
When you open a page with Web Workers, open the Chrome Dev Tools (F12), look on the right at the Workers tab, check the radio box and reload the page. This will pop-up a small window for tracing the execution of each worker. In these windows, you can set breakpoints, inspect variables, log messages, etc. Here is a screenshot of a debugging session with the prime numbers example:
FireFox has similar tools, see Firefox developer tools.