Skip to content

Dedicated Web Workers

new Worker(url) takes a URL pointing to a JavaScript file. The browser downloads that file and runs it in an isolated background thread. In these lessons, instead of hosting a separate file, we generate the URL on the fly from a Blob — this keeps everything self-contained and runnable inline.

// worker.js (separate file)
self.onmessage = function(e) {
const result = heavyCompute(e.data);
self.postMessage(result);
};
// main.js
const worker = new Worker('/worker.js');
worker.onmessage = function(e) { console.log('result:', e.data); };
worker.postMessage(inputData);
  • worker.postMessage(data) — send data to the worker from the main thread
  • worker.onmessage = fn — receive data from the worker on the main thread
  • self.onmessage = fn — (inside the worker) receive data from the main thread
  • self.postMessage(data) — (inside the worker) send a result back to the main thread
  • worker.terminate() — immediately stop the worker from the main thread; the worker gets no warning

Instead of a separate file, you can define the worker source as a string, wrap it in a Blob, and convert that to an object URL with URL.createObjectURL. The resulting URL looks like blob:https://example.com/uuid and behaves exactly like a hosted file URL. After the worker is no longer needed, call URL.revokeObjectURL(url) to free the memory.

The worker below sums all integers from 1 to N. With N = 1 000 000, this is a non-trivial loop that would briefly block the main thread if run inline — here it runs in a background thread instead.

Browser Storage
OptionBenefitCost
Processing in a Web WorkerTrue parallelism — a background thread separate from the main thread keeps the UI responsive during heavy workCommunication cost via postMessage (structured clone), plus the overhead of creating/destroying the worker
Processing directly on the main threadSimple, immediate DOM access, no cross-thread communication costHeavy work blocks the UI thread, causing the page to freeze or drop frames
Inline worker via a Blob URLNo separate file to host — code lives in one place, easy to deployHarder to debug than a real file since there’s no straightforward source map or breakpoint
  • Expecting a worker to access the DOM — a worker has no window, document, or any DOM API at all. This is the most common beginner misunderstanding; postMessage the result back and let the main thread handle the DOM instead.
  • Forgetting to call worker.terminate() — a worker that’s never terminated stays in memory and keeps consuming CPU even after its work is done, causing a memory leak, especially if you keep creating new workers.
  • Using a worker for short work that takes less than a few milliseconds — the cost of creating the worker and round-tripping a postMessage outweighs the benefit. Reserve workers for work that’s long enough to justify the overhead.
Which identifier refers to the global scope inside a Web Worker?
What does worker.terminate() do?
Why do we use URL.createObjectURL(new Blob([src])) in these lessons?