HTML5 Web Workers: Classic Message Passing Concurrency

February 5, 2012


Most concurrency frameworks I write about on this blog consist of numerous layers of abstraction. Consider the Task Parallel Library, for instance: it’s a wrapper on top of the .NET Thread Pool, which is a wrapper on top of Windows threads. This cruft of low-level abstraction layers forces certain expectations from the newer libraries – namely, they must allow direct access to shared state, provide synchronization mechanisms, volatile variables, atomic synchronization primitives, …

It seems that JavaScript (HTML5) with its Web Workers standard enjoys the lack of abstraction cruft for threading in the JavaScript world. Because there are no underlying low-level libraries for multithreaded JavaScript computation (in the browser), Web Workers are free to reinvent not only the APIs, but also the concurrency style.

Web Workers provide a message-passing model, where scripts can communicate only through well-defined immutable messages, do not share any data, and do not use synchronization mechanisms for signaling or data integrity. Indeed, Web Workers are not ridden with classic concurrency problems such as deadlocks and race conditions – simply because these concurrency problems are impossible.

Frankly, I’m a little jealous of JavaScript developers who can now leverage multithreading in their browser-side applications. The Web Workers API is minimalistic but done right. Below is a small example of a multithreaded prime number search with Web Workers – if you are looking for a more detailed introduction and walkthrough, check out the following resources:

First, the UI:

<input type="text" id="range_start"
       placeholder="start (e.g. 2)" /><br/>
<input type="text" id="range_end"
       placeholder="end (e.g. 100000)" /><br/>
<label for="dop">Degree of parallelism:</label>
<input type="range" id="dop"
       min="1" max="8" value="4" step="1" /><br/>
<input type="button" id="calculate" value="Calculate" />


Now the actual business. When the “Calculate” button is clicked, we spawn the specified number of worker threads to do the calculation in the background. The main thread passes to the workers the range of primes they will work on, and receives from the workers progress reports and the final count:

//Some parts of the code elided for clarity
$(document).ready(function () {
    $("#calculate").click(function (e) {
        var rangeStart = parseInt($("#range_start").val());
        var rangeEnd = parseInt($("#range_end").val());
        var parallelism = parseInt($("#dop").val());
        createWorkers(parallelism, rangeStart, rangeEnd);
function createWorkers(parallelism, start, end) {
    var range = end – start;
    var chunk = range / parallelism;
    var count = 0;
    var done = 0;
    for (var i = 0; i < parallelism; ++i) {
        var worker = new Worker("prime_finder.js");
        worker.onmessage = function(event) {
            if ( === ‘DONE’) {
                count +=;
                if (done == parallelism) …
            } else if ( === ‘PROGRESS’) {
                var progress =;
        var init = {
            start: start + i*chunk,
            end: start + (i+1)*chunk,
            idx: i

Note the communication between the threads. The main thread uses Worker.postMessage to provide data to the worker thread, and receives from it status updates using the onmessage event. The worker thread runs the prime_finder.js script:

//The isPrime function elided for brevity
self.onmessage = function (event) {
    var start =;
    var end =;
    var size = end – start;
    var count = 0;
    for (var i = start; i < end; ++i) {
        if (isPrime(i)) ++count;
        if (i % 1000 === 0) {
                type: ‘PROGRESS’,
                value: 100.0*((i-start)/size),
        type: ‘DONE’,
        count: count,

Here we see the opposite direction – the worker thread periodically posts progress reports and eventually reports completion. The whole thing is triggered by the receipt of the initial message from the main thread.

(In this screenshot you can see how uneven the distribution of work turns out to be – the first thread finishes very quickly while the fourth thread lags behind quite slowly…)

To experiment with this code, you can download the full demo, including a very small Node.js server that serves it.

If you have a C# or C++ development background, it all probably feels very unnatural to you. Where is the shared state? Where are the synchronization mechanisms? Where are the function pointers? – Indeed, it can be scary to write a multithreaded program using only asynchronous message passing – but it’s a much cleaner start than many of the libraries we have today.

I am posting short updates and links on Twitter as well as on this blog. You can follow me: @goldshtn
This blog post was also cross-posted to .

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>



  1. David NelsonFebruary 6, 2012 ב 7:16 PM

    I don’t envy JavaScript developers at all. It is trivial to write multi-threaded code in C# using a message passing style if that is what you want to do. But C# ALSO has the ability to use shared state and synchronization where it is appropriate (and there are many such cases). Being less powerful and less functionally complete does not make JavaScript better.

  2. peterFebruary 6, 2012 ב 10:00 PM

    Why is the distribution uneven?

  3. Sasha GoldshteinFebruary 7, 2012 ב 10:14 AM

    @David: “Better” is relative 🙂 For experienced developers with a strong background in operating systems, cache coherence protocols, and synchronization mechanisms — I agree that the “traditional” way is more flexible and more powerful. Most developers I know, however, abuse that power due to lack of that strong background…

    @peter: Because the “isPrime” implementation is very naive — it checks all possible factors from 2 to n-1.

  4. Pingback: How to Build Websites » What is a Web Worker on HTML5?