Web Workers

Runs JavaScript on a separate thread for CPU-bound work, communicating with the main thread only via message passing.

                new Worker(url) / worker.postMessage(data) / self.onmessage = handler
              

Purpose

A web worker runs JavaScript on a genuinely separate thread, useful for CPU-heavy work that would otherwise block the main thread and freeze the UI. Workers have no access to the DOM and communicate with the main thread purely through message passing.

Syntax

// main.js
const worker = new Worker('calc-worker.js');
worker.postMessage({ numbers: [1, 2, 3] });
worker.onmessage = (event) => console.log('Result:', event.data.result);

// calc-worker.js
self.onmessage = (event) => {
  const result = event.data.numbers.reduce((sum, n) => sum + n, 0);
  self.postMessage({ result });
};

Behavior notes

  • Data passed to postMessage is copied via the structured clone algorithm (recall structuredClone()), not shared by reference — a worker can never directly mutate the main thread’s objects, and vice versa.
  • A worker has no access to the DOM, window, or the main thread’s variables — it’s an isolated execution context, only reachable via messages.
  • SharedArrayBuffer (Advanced tier) is the exception to the copy-only rule, enabling true shared memory between a worker and the main thread — a specialized tool with its own cross-origin- isolation requirements, not a default choice.
  • Starting a worker has real overhead — worth it for genuinely CPU-heavy work, not for every small task.

Common mistakes

  • Expecting to manipulate the DOM from inside a worker — it isn’t available there at all.
  • Passing a very large object to postMessage on every message when only a small piece of it actually changed, incurring repeated structured-clone copying cost.

Runtime notes

Standard in every current browser; Node has its own separate worker_threads module with a similar message-passing model, covered in the Node module of this tier.

Taught in these lessons

Related reference