Read first

A Web Worker runs a JavaScript file on a separate thread, so heavy work doesn’t freeze the page. It has its own event loop and its own global scope.

How it works

// main.js (in the page)
const worker = new Worker('worker.js');
worker.postMessage({ n: 40 });
worker.onmessage = (e) => console.log('result', e.data);
 
// worker.js
self.onmessage = (e) => {
  const fib = (n) => (n < 2 ? n : fib(n - 1) + fib(n - 2));
  self.postMessage(fib(e.data.n));    // heavy work, but the page stays smooth
};
  • Messages are copied (structured clone), not shared. Large binary data can be transferred instead (an ArrayBuffer moves to the worker and becomes unusable on the sending side), which avoids the copy.
  • Workers cannot touch the DOM. They compute; the page updates the UI with the result.
  • Real shared memory exists (SharedArrayBuffer with Atomics), but browsers only allow it on cross-origin isolated pages.
  • Node.js has the same idea in worker_threads.

When to use one

Parsing big files, image processing, heavy maths, search indexing: anything that would take more than ~50 ms on the main thread. Not for network calls: those already happen outside your thread.

Check yourself