/

Web Workers: Running JavaScript Code in the Background

Web Workers: Running JavaScript Code in the Background

Web Workers provide a way to run JavaScript code in the background, allowing for parallel execution inside the browser. This is useful in scenarios where synchronous JavaScript execution may cause performance issues. In this article, we will explore the use of Web Workers, how to communicate with them, their lifecycle, how to load libraries, and the available APIs.

Introduction

JavaScript is single-threaded, meaning that only one task can be executed at a time. While this has its advantages in terms of simplicity, it can also limit the performance of JavaScript applications. Web Workers address this limitation by introducing the possibility of parallel execution.

However, Web Workers come with a few limitations. They have no access to the DOM (Window and Document objects), can only communicate with the main JavaScript program through messaging, need to be loaded from the same origin, and do not work when served using the file protocol.

Browser Support for Web Workers

Web Workers have good browser support. You can check for Web Workers support using the following code snippet:

1
2
3
if (typeof Worker !== 'undefined') {
// Web Workers are supported
}

Create a Web Worker

To create a Web Worker, you need to initialize a Worker object and load a JavaScript file from the same origin.

1
const worker = new Worker('worker.js');

Communication with a Web Worker

There are two main ways to communicate with a Web Worker:

  1. Using the postMessage API offered by the Worker object.
  2. Using the Channel Messaging API.

Using postMessage in the Web Worker object

You can send messages to a Web Worker using the postMessage method on the Worker object. Here’s an example:

1
2
3
// main.js
const worker = new Worker('worker.js');
worker.postMessage('hello');
1
2
3
4
5
6
7
8
// worker.js
onmessage = event => {
console.log(event.data);
}

onerror = event => {
console.error(event.message);
}

A worker can also send messages back to the main thread using its global postMessage() function:

1
2
3
4
5
6
7
// main.js
const worker = new Worker('worker.js');
worker.postMessage('hello');

worker.onmessage = event => {
console.log(event.data);
}

If you want to set up multiple listeners for the message event, you can use addEventListener instead of onmessage:

1
2
3
4
5
6
7
8
9
10
11
12
13
// worker.js
addEventListener('message', event => {
console.log(event.data);
postMessage('hey');
}, false);

addEventListener('message', event => {
console.log(`I'm curious and I'm listening too`);
}, false);

addEventListener('error', event => {
console.log(event.message);
}, false);

Using the Channel Messaging API

Instead of using the built-in postMessage API, you can use the more general-purpose Channel Messaging API to communicate with Web Workers.

1
2
3
4
5
6
7
8
9
// main.js
const worker = new Worker('worker.js');
const messageChannel = new MessageChannel();

messageChannel.port1.addEventListener('message', event => {
console.log(event.data);
});

worker.postMessage(data, [messageChannel.port2]);
1
2
3
4
// worker.js
addEventListener('message', event => {
console.log(event.data);
});

A Web Worker can send messages back by posting a message to messageChannel.port2:

1
2
3
addEventListener('message', event => {
event.ports[0].postMessage(data);
});

Web Worker Lifecycle

Web Workers are launched and will be shut down as soon as their code is run through completion, unless they stay in listening mode for messages through worker.onmessage or by adding an event listener. You can stop a Web Worker using its terminate() method from the main thread or close() method from within the worker itself.

1
2
3
4
// main.js
const worker = new Worker('worker.js');
worker.postMessage('hello');
worker.terminate();
1
2
3
4
5
6
7
8
9
// worker.js
worker.onmessage = event => {
console.log(event.data);
close();
}

worker.onerror = event => {
console.error(event.message);
}

Loading Libraries in a Web Worker

Web Workers can use the importScripts() global function to load libraries in their global scope.

1
importScripts('../utils/file.js', './something.js');

APIs Available in Web Workers

While Web Workers do not have access to the DOM, they can use many other APIs, including:

  • XHR API
  • Fetch API
  • BroadcastChannel API
  • FileReader API
  • IndexedDB
  • Notifications API
  • Promises
  • Service Workers
  • Channel Messaging API
  • Cache API
  • Console API (console.log() and friends)
  • JavaScript Timers (setTimeout, setInterval, etc.)
  • CustomEvents API (addEventListener() and removeEventListener())
  • Current URL (accessible through the location property in read mode)
  • WebSockets
  • WebGL
  • SVG Animations

tags: [“Web Workers”, “JavaScript”, “parallel execution”, “DOM limitations”, “messaging”]