fbpx Skip to content

Aquent | DEV6

Web Workers

Written by: Shane Whittaker

What are Web Workers?

The JavaScript code that you write will usually execute in a single thread. Web workers are JavaScript scripts that run as a background process in a web application, independent of other user-interface scripts that may also have been executed from the page. This means you are able to run long running CPU intensive tasks without having to interrupt the flow of using a web application, making them multi-threaded.

Web Worker Types:

The specification notes that there are three types of Web Workers:

  1. Dedicated Worker – a worker that is only accessible by the process that originally called/created it
  2. Shared Worker – a worker that can be accessed by all processes from the same origin, such as several windows, iframes or even other workers
  3. Service Worker – an event-driven worker registered against an origin and a path

How do you actually use a worker?

All current browsers support using web workers (see support here) and they work by sending data between the main process and the worker via a system of messages, as a string or a JSON object, where both sides send their messages by utilizing postMessage(). The worker in turn responds to messages via the onmessage event handler.

Note: postMessage() can be used to send messages between other JavaScript contexts running in a browser; it’s not just for web workers.

Here is the code to create a web worker:

var worker = new Worker('theWorker.js');

Now you know how to create a web worker, but that doesn’t say much about how web workers actually communicate throughout the execution of the process, so here’s an example to give more context around how simple it is to set up and use a web worker:

var worker = new Worker('theWorker.js');
 
 worker.addEventListener('message', function(event) {
   document.getElementById('message').textContent = 'The Worker says: ' + event.data;
 }, false);
 
 worker.postMessage('Hello Dev6!');

And here is the code in theWorker.js:

self.addEventListener('message', function(event) {

   self.postMessage(event.data);
   self.close();
 
 }, false);

Note that the message is contained within the Message event’s data attribute and when the data is being passed through the process it is copied rather than shared. Also, if you want to terminate a worker, this can be done with the use of the close() method in the worker or via the main process using the terminate method.

// Terminate a worker from the main thread
 worker.terminate();
 
 // Terminating the worker itself.
 self.close();

What happens if there’s an error?

An ErrorEvent is triggered whenever an error occurs when running a worker. The error interface contains three properties:

  1. lineno – the line number where the error occurred
  2. filename – the name of the worker script causing the error
  3. message – a description of the error. 

Below is a snippet that creates two handles, one for the error and another for handling the messaging from the worker. If the worker encounters an error, it will display in the DOM detailing the line the error originated on, the file name of the script that caused the error and a meaningful description of the error.

function handleError(event) {
   document.getElementById('error-message').textContent = 'ERROR found on line: ' +
      event.lineno + ' in file: ' + event.filename + '. Msg(' + event.message + ')';
 }
 
 function handleMessage(event) {
   document.getElementById('message').textContent = event.data;
 }
 
 var worker = new Worker(theWorker.js');
 worker.addEventListener('message', handleMessage, false);
 worker.addEventListener('error', handleError, false);
 worker.postMessage();//This should trigger the error

Because web workers are multi-threaded, here are a few features that are available to web workers:

  • The navigator object
  • setTimeout()/clearTimeout()
  • setInterval()/clearInterval()
  • The location object (read-only)
  • The Application Cache
  • Importing external scripts using the importScripts() method
  • XMLHttpRequest
  • Spawning other web workers


Unfortunately, web workers don’t have access to things like:

  • The DOM (because it is not thread-safe)
  • The parent object e.g parent.document.body.style
  • The window object eg. window.activeElement
  • The document object e.g document.addEventListener()

This means that in order to perform any operation that utilizes these, the worker would have to pass the data through the postMessage() method.

In conclusion, it’s important to mention that web workers allow us to create more responsive web applications that can harness the power of the client while taking full advantage of new technologies without having to be concerned with a diminished user experience.

Reference:

Spec – https://html.spec.whatwg.org/multipage/workers.html

Workers as ES6 – https://www.codedread.com/blog/archives/2017/10/19/web-workers-can-be-es6-modules-too/