Multi-threading in JS, and what you can do with it!

Introduction

Sam Hendrickx
Raccoons Group
5 min readFeb 21, 2022

--

At Wheelhouse, we usually go out of our way to try out new things or technologies. Especially since we’re always looking for new things to do with JavaScript. We’re on our way towards understanding the Worker API better. In the process, we’re getting our hands dirty with the likes of Web Assembly and Audio Worklets. So we’re making a blog on the fundamentals of the Worker API in JavaScript to get a better basic understanding of what it does and can do for us as developers.

Multi-threading in JS?

The main thing you’ll hear when people ask the question: “Is JavaScript multi-threaded”, is plain and simple: “No”. -“JavaScript in itself can do no such thing!” Contrary to other programming languages — like C#, Java, Go, or even plain old C++ — JavaScript (and other interpreted languages like Python) do not provide an API for — or come out of the box with — multi-threaded functionality.

The people that say these things are absolutely correct. In no way is it indicated in the specs and in the near future for JavaScript to natively support multi-threading. So this blog stops right here then? Not exactly. There is in fact a way to actually get around to run code in JavaScript on a separate thread, and the performance benefits are awesome!

What about async?

Yes, JavaScript supports asynchronous execution of code, but that is different from multi-threading. Asynchronous programming makes it possible for a specific piece of code to execute seemingly parallel to other code.

This is what the Promise we’re all already quite familiar with does. JavaScript will schedule the block of code that’s asynchronous to a later stage, when that Promise gets resolved (i.e.: a successful network request).

Still, the individual lines of code — broken down into their instructions for the CPU — will still run through it sequentially. None of it is actually happening side-by-side. In other words: async allows us as developers to program in a way that provides an abstraction to parallel programming, but really, it isn’t.

Web Workers

You were probably thinking this part would come, or would otherwise be very confused. Yes, of course, the Web Worker API is a game-changer in this aspect. This isn’t something specific to JavaScript, or even something new. This is a browser API, and not every browser has every type of Worker implemented per se, like Audio Worklets for example.

Anyway, Web Workers are cool. Because the browsers have their foot down on OS-level and can allocate memory and threads as much as they like, they can provide a workspace for code to run on a separate thread also! This is essentially what the Worker API does for you. You may create a worker and give it some code to execute on a separate thread, allow it to talk back to the main application thread, and have a party!

Demo Time

Web Worker API demonstration by Rafaël Mindreau

We’ve visualised how this works and looks like in the browser in the following demonstration.

In a nutshell: You can schedule some work in the demo. Work in the form of prime number discovery. It will count up to a limit defined by the primes slider. It will list all the primes it finds on the way. This is the work that needs to be performed by the machine. You can schedule the work on the main thread or on the separate thread.

Observations

You will find that, when you schedule a lot of work on the main thread, the UI locks up! It’s quite devastating for UX were this to happen in your app. The slider won’t work, but you might notice that you can still scroll, because this is not part of the rendering loop. When scheduling more than one task, you will see that it tries to crunch it at a one-by-one pace. This is the JavaScript we’re used to.

On the other hand, the green button allocates a new worker (and thus thread) to work on its own, separate from the thread handling the critical rendering path of the browser. You might notice you’re free to do in the UI whatever you want to do! Also, it’s important to note that the tasks will finish in parallel now because that’s what’s really going on! It’s actually multi-threading all of that number-crunching for you.

Also, the same work performed on the main thread finishes slower than that same work on a separate thread. I speculate that this is because there is other work to be done on the main thread away from the UI or even the app in question.

Benefits

The toughest bit in this, is knowing how you can use this. Essentially there shouldn’t be a use-case for it in the first place. That’s the thing I hear most of the time. Since you don’t usually want to do heavy number-crunching in your front-end. That is usually something your back-end should handle before sending the data ready for consumption to the front-end.

But we don’t live in an ideal world, and I used to work for a company where the API was something that grew very organically as time progressed. A very familiar story. I remember we had to populate a table with huge amounts of data. Data that — at that point — was already loaded in store, but required mapping and some computational aspect to it before it could be displayed. The UI locked up. We could have created a separate endpoint in the back-end to give us the data we required and just display that, but that team would defend themselves and say that the cost of transporting the same data twice was ridiculous. Eventually, we had to come up with a way to deal with that, but thinking back about it right now, we could have used Web Workers to at least prevent the UI from locking up.

Conclusion

Web Workers are cool! Definitely! The thing is that you won’t see them in production that much. Which is OK, but we shouldn’t forget that it works, and does so quite well! If your UI locks up, and it’s not due to recursion or an infinite loop, you should be thinking of loading that work off to separate threads. Have a blast!

We’ll probably go into more detail on Audio Worklets and Web Assembly to reveal that applications in the browser can be truly powerful and seamless. More on that in a future blog… 🎉

--

--