Multithreaded Javascript

For the longest time, Javascript has always been implemented using a single thread in your browser. For the most part, this wasn’t a problem. If you’re just using javascript for simple DOM manipulations or form submissions then a single thread is all you need. However, once developers started getting more advanced with their Javascript usage, this eventually led to an issue.

Let’s say I have the following single page application (SPA) that shows a list of prime numbers from 1 to 600,000:

Index.html

<!DOCTYPE html>
<html lang="en">
 <head>
 <title>Multithread Example</title>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 </head>
 <body>
 <h1>List of Primes from 1 to 600000</h1>
 <ul>

</ul>
 <script src="./single-thread.js"></script>
 </body>
</html>

My Index.html has an empty element that I want to append all the primes that I find to it. I call my single-thread.js file which does all the work.

Single-Thread.js

function isPrime(n) {
 if (n > 1) {
 for (let i = 2; i < n; i += 1) {
 if (n % i === 0) {
 return false;
 }
 }
 return true;
 }

return false;
}

(function () {
 for (let i = 1; i < 600000; i += 1) {
 if (isPrime(i)) {
 const li = document.createElement('li');
 li.innerHTML = i;
 document.querySelector('ul').appendChild(li);
 }
 }

}());

My single-thread.js file loops through all the numbers from 1 to 600,000 and prints out any prime that it finds and appends it to the element.

The Single Thread Problem

If you run this in your browser, it will work as intended (printing out all the primes from 1 to 600,000) but will cause for a terrible user experience. The UI will simply lock up until this script finishes executing. In fact, Chrome might even warn you that the page has become unresponsive. So even though I am telling Javascript to append my number to the list in the loop, all UI rendering gets paused until the script completes. Thus, the user is just staring at a blank loading window.

Multithreaded Javascript Using Web Workers

Javascript Web Workers are the solution to this problem. A Web Worker is basically a task that runs in the background, separate from the UI thread. From the Web Worker, you can pass messages back and forth from the UI thread. Let’s redo the previous example using Web Workers.

Multi-thread.js

Create a new file called Multi-thread.js and post the following in there:

if (window.Worker) {
 const myWorker = new Worker('./single-thread.js');
 myWorker.onmessage = function (e) {
 const li = document.createElement('li');
 li.innerHTML = e.data;
 document.querySelector('ul').appendChild(li);
 };
}

The if statement checks to see if the browser supports web workers. Unsurprisingly, browsers that are running IE 9 or older do not support Web Workers.

I then initialize a new Web Worker by calling my single-thread.js in the worker’s constructor. You can initialize as many workers as you want. Finally, for my worker, I implement an onMessage callback. This is so I can handle any messages passed from my web worker back to my multi-thread.js file. Anything that I do in this file will run on the UI thread. In this case, I append the result to the element.

Single-thread.js

I made the following changes to my single-thread.js file:

function isPrime(n) {
 if (n > 1) {
 for (let i = 2; i < n; i += 1) {
   if (n % i === 0) {
    return false;
   }
  }
  return true;
 }
 return false;
}

(function () {
 for (let i = 1; i < 600000; i += 1) {
  if (isPrime(i)) {
   <strong>postMessage(i);</strong>
  }
 }
}());

The only thing that I changed was calling the postMessage() function (and removing the append). Although this function is part of the window’s properties, you don’t have to call it with window.postMessage() because you are already inside of a Web Worker context.

Index.html

Finally, make sure that you change your index.hmtl to point to the mult-thread.js file instread of your single-thread.js file:

<script src="./multi-thread.js"></script>

The result

In order to make this work, you need to make sure that you are **running in a web server. **Loading the files through your documents directory in your browser will give you a cross origin exception in Chrome and Firefox.

Once everything is set up and you access the webpage, you will notice that items get appended to the list as soon as a new prime number is found. Unlike before, the user is not staring at a blank window and they can see the list getting updated in real-time.

You can view the full project on GitHub.