Image from playembbeded.com

Multithreading Javascript

A Look Into Web Workers

Max Peng
Hackmamba
Published in
4 min readSep 15, 2017

--

As you may probably know, Javascript is single-threaded. To clarify better, this means that one single thread handles the event loop. For older browsers, the whole browser shared one single thread between all the tabs. Modern browsers improved upon this by using either process-per-site-instance or different threads per tab. Although dedicated threads improved the responsiveness of webpages, it still left each tab unable to handle multiple scripts running at once.

You may be wondering, why would we need multiple scripts running at once?

Computers are extremely fast and with each tab using its own thread, webpages should have no problems. This is true for most cases until your browser runs a complex algorithm or renders an intricate visualization. These laborious processes end up blocking the main thread which slows down UI events and triggers. Good thing in 2009, Javascript introduced a hot new toy, Web Workers, to deal with this problem.

So what are Web Workers?

Web Workers are Javascript scripts executed from an HTML page that runs on a background thread away from the main execution thread. Data is sent between the main thread and workers through messages. Since these workers run on a separate thread than the main execution thread, you can utilize web workers to run process intensive tasks from the browser without creating blocking instances.

Cool right? Let us build some.

Its pretty simple to spawn a Web Worker. First we need to start with two files: a main file and a file that contains the code that the worker will run. The separate files are necessary because the web worker code will need to be run in an isolated thread. Let us name the files main.js and worker.js. To create a new Worker object, we will pass in the path of the worker file into the Worker constructor like so:

// main.jsvar worker = new Worker('worker.js');

Now that we have a worker, let us send it a message. To do so we will have to call the postMessage() function on the worker object.

// main.jsworker.postMessage('Happy Birthday');

At this point I should probably point out a caveat of web workers. The data sent between the main thread and the workers are copied rather than shared. We should keep this in mind when thinking about memory allocation and the speed of data transfer.

Now for our worker to hear the ‘Happy Birthday’ message, we will have to set an event listener in the worker.js file for the message event.

// worker.jsself.addEventListener('message', function(e) {
// code to be run
}

Once the worker file hears a message event, it runs the code within the function block. Just write it like any other normal function but instead of returning a variable send a message back to the main thread with a postMessage() function. We can use the data from the sent message with e.data.

// worker.jsself.addEventListener('message', function(e) {
var message = e.data + 'to myself!';
self.postMessage(message);
}

In the above code, we are sending the message, ‘Happy Birthday to myself!’ back to the main execution thread. As a result, we will also need a message event listener in the main file to receive the data and act upon it. Here is the final main.js file:

// main.jsvar worker = new Worker('worker.js');worker.addEventListener('message', function(e) {
console.log(e.data);
}
worker.postMessage('Happy Birthday');

In this example, we will console.log ‘Happy Birthday to myself!’. A helpful tip is that while the order of worker.addEventListener and worker.postMessage does not matter, it makes logical sense for us to create the ability to listen to a message before sending one out.

Finally we would like to close the worker thread, which we can do be adding a self.close() function in the worker file. Here is the final worker.js:

// worker.jsself.addEventListener('message', function(e) {
var message = e.data + 'to myself!';
self.postMessage(message);
self.close();
}

Lets go through what just happened:

  1. Our application created a web worker in main.js which runs the code from worker.js
  2. It sends the worker a message with the string ‘Happy Birthday’
  3. The worker, which had an event listener for ‘message’, received the message and ran the code within.
  4. The worker appended ‘to myself!’ to the message data creating ‘Happy Birthday to myself!’ and sends that as data within a message back to main.js
  5. Main.js, which also had an event listener for message, than console.log ‘Happy Birthday to myself!’.

Easy!

The following code uses web workers to split up the processing for solving n-queens:

Feel free to play around with it! A note for testing web workers, for security reasons Chrome does not allow you to deploy web workers locally. Use Firefox instead.

--

--