Web workers to execute JavaScript in parallel

- 👤 Andrés Cruz

🇪🇸 En español

Web workers to execute JavaScript in parallel

View example Download

Web workers allow you to execute sections of JavaScript code from files in parallel on a separate thread; generally, when building a web application, web page, etc., all JavaScript code runs on a single thread created by the browser. However, when performing blocking or high-processing tasks, it is advisable to execute them outside of this thread to avoid affecting this main thread.

JavaScript is a single-threaded language, meaning all code normally runs on a single thread: the browser's main thread.
The problem is that when we execute heavy tasks (such as complex calculations, data processing, or intensive loops), the interface freezes, clicks stop responding, and the user experience worsens.

This is where Web Workers come in.

Web Workers allow you to run JavaScript code in the background, on a separate thread from the main thread. Thanks to this, we can execute heavy tasks without blocking the interface.

Web workers provide a simple mechanism for running JavaScript code in the background.

In this guide, you will learn:

  • ✔️ What Web Workers are
  • ✔️ How they work
  • ✔️ How to communicate with them
  • ✔️ Real practical example
  • ✔️ Error handling
  • ✔️ Limitations
  • ✔️ Best practices

Now, learn how to run JavaScript in parallel with workers.

What is a Web Worker?

A Web Worker is a browser mechanism that allows you to run JavaScript on a thread independent of the main thread.

This means we can:

  • Perform high-processing tasks
  • Avoid UI freezes
  • Improve application performance

Meanwhile, the user can continue interacting with the page without noticing delays.

❓ When should you use Web Workers?

Use them especially when your application needs to:

  • Process large volumes of data
  • Execute heavy mathematical algorithms
  • Render or manipulate images
  • Process massive JSON files
  • CPU-intensive operations

If your code takes more than 50 ms to execute, it could affect performance (INP / UX). In those cases, a Web Worker can be the ideal solution.

Types of Web Workers

There are mainly two types:

✔️ Dedicated Worker

It is the most common.

It can only be used by the page that creates it.

const worker = new Worker("worker.js");

✔️ Shared Worker

It can be shared between several tabs or windows.

Getting started with web workers

As we indicated at the beginning, web workers run in an isolated process (in parallel); furthermore, the code we want to execute in parallel must be in a separate file which will be downloaded asynchronously. To create our web worker, we must create an object from the Worker class as follows:

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

Simply creating an object of the Worker class and specifying the file to load is enough to create a web worker.

Web Workers are not the same as Service Workers.

Service Workers are focused on cache, offline, and networking.

Getting Started with Web Workers: Message passing between the main thread and the web worker

To create a worker, simply specify the JavaScript file that will run in the background:

var worker = new Worker("task.js");

From that moment on, task.js runs on a separate thread.

In addition to running JavaScript code on a separate thread, web workers offer a simple mechanism for message passing between this separate thread or process and the main thread.

This mechanism is very simple and useful to use, where passing a message from the main thread triggers an event in the web worker.

Send data to the Worker

To pass a message from the main thread to a Worker, the postMessage() method is used:

value = 50; var myWorker = new Worker("task.js"); myWorker.postMessage(value);

And as we saw in the previous example, this message passing actually allows us to pass data from the main thread to the Worker.

Receive data from the Worker

To be able to see the messages that the Worker returns to the main thread, the onmessage property is used:

value = 50; var myWorker = new Worker("task.js"); myWorker.postMessage(value); myWorker.onmessage = function (oEvent) { console.log("Prime numbers: " + oEvent.data); };

Practical example: Worker to generate prime numbers

Suppose we want to calculate all prime numbers up to a given value.

If we do it on the main thread, the browser might freeze.

The following JavaScript code allows determining all the primes that exist from zero up to a given value:

function checkPrimo(number) { var divisor = 1; var primo = 0; for (var i = 0; i <= number; i++) { if (number % i == 0) { primo++; } if (primo > 2) break; } if (primo == 2) { return true; } else { return false; } } // function to determine if a set of numbers are prime function checkPrimoCota(number) { primos = ""; for (i = 0; i <= number; i++) { if (checkPrimo(i)) primos += i + " "; } return primos; }

And when passing a message to the web worker from our main page:

postMessage("Starting to work!"); onmessage = function (oEvent) { postMessage("Received the following value: " + oEvent.data); postMessage("The following are primes: " + checkPrimoCota(oEvent.data)) };

See the practical example in the download links at the beginning and end of this entry.

Code in the main thread

let value = 20000; let myWorker = new Worker("task.js"); myWorker.postMessage(value); myWorker.onmessage = function(e) { console.log(e.data); };

Errors handled by Workers

Just as with message passing, to handle errors you must use a property called onerror:

value = 50; var myWorker = new Worker("task.js"); myWorker.postMessage(value); myWorker.onmessage = function (oEvent) { console.log("Prime numbers: " + oEvent.data); }; myWorker.onerror = function (oEvent) { console.log("An error occurred in file: " + oEvent.filename + " on line " + oEvent.lineno + " " + oEvent.message); };

Where:

  • filename: Name of the script that caused the error.
  • message: The error caused.
  • lineno: Line where the error occurred.

Considerations about web workers

Web workers CANNOT access:

  • DOM.
  • window object.
  • document object.
  • parent object.

It is necessary for the JavaScript code to be executed by the web workers to be in separate files.

To close web workers, we use the close method.

To verify browser support for web workers:

if(typeof(Worker) !== "undefined") { // Supports Web Workers // Create our web workers } else { // Does not support Web Workers }

⚠️ Limitations of Web Workers

A Web Worker CANNOT access:

  • ⛔ DOM
  • ⛔ window
  • ⛔ document
  • ⛔ parent

In addition:

  • ✔️ The Worker code must be in a separate file
  • ✔️ They are downloaded asynchronously
  • ✔️ They cannot directly manipulate the UI

Closing a Web Worker

From the main thread:

myWorker.terminate();

From the worker:

close();

Web Worker Compatibility

Before using it:

if (typeof Worker !== "undefined") { // Supports Web Workers } else { // Does not support Web Workers }


Today, most modern browsers support them.

Best practices

  • ✔️ Use them for truly heavy tasks
  • ✔️ Do not create Workers inside loops
  • ✔️ Terminate Workers when they are no longer in use
  • ✔️ Send only the necessary data
  • ✔️ Consider using Transferable Objects for high performance

Web Workers in JavaScript are an excellent tool for avoiding main thread blocks and improving the performance of your web applications.

The next API we'll look at is the one for detecting light events using JavaScript.

Conclusions

Web workers can become a great tool to avoid blocking processes in our JavaScript. By achieving parallel code execution, we can achieve better performance for our web applications.

By executing tasks in parallel:

  • ⭐ The UI stays fluid
  • ⭐ We improve the user experience
  • ⭐ We increase overall performance

You can see the full example at the following links:

View example Download

I agree to receive announcements of interest about this Blog.

Web workers allow code sections of JavaScript files to be executed in parallel in a separate thread; In this entry we will see how to work with web workers.

| 👤 Andrés Cruz

🇪🇸 En español