Explain what Web Workers are, how message passing works (structured clone + Transferables), and the key constraints (no DOM). Include a real scenario, trade-offs (startup + message overhead), and common pitfalls like leaks or copying huge payloads.
Web Workers: Off-Main-Thread JavaScript
Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.
What is a Web Worker?
A Web Worker runs JavaScript on a separate thread from the main UI thread. Use it for CPU-heavy work (parsing, compression, image processing) so the UI stays responsive and scrolling stays smooth.
Real-world scenario
Example: you need to parse a 50MB JSON export and compute stats while the user keeps scrolling. Doing this on the main thread will jank the UI. Offload the parsing + aggregation to a worker, then send the small result back to the UI thread.
Capability | Main Thread | Worker |
|---|---|---|
DOM access | Yes | No |
Heavy compute | Blocks UI | Safe (off-thread) |
Communication | postMessage/onmessage | postMessage/onmessage |
Globals | window/document | self (no DOM) |
How communication works
Workers communicate via postMessage. Data is copied using the structured clone algorithm, or transferred using Transferables (e.g., ArrayBuffer) to avoid expensive copies. Functions and DOM nodes cannot be cloned.
// main thread
const worker = new Worker('worker.js');
// Transfer ArrayBuffer to avoid copy
const buffer = new Uint8Array([1,2,3]).buffer;
worker.postMessage({ type: 'analyze', buffer }, [buffer]);
worker.onmessage = (e) => {
console.log('result', e.data);
};
// worker.js
self.onmessage = (e) => {
const view = new Uint8Array(e.data.buffer);
const sum = view.reduce((a,b) => a + b, 0);
self.postMessage({ sum });
};
Lifecycle + error handling
Workers are long-lived by default. Terminate them when done (worker.terminate()) to avoid leaks. Handle errors with worker.onerror and worker.onmessageerror so failures do not silently disappear.
When to use (and when not to)
Use workers for CPU-heavy tasks or large data transforms. Avoid them for small tasks where the startup cost + message overhead outweighs the benefit. For I/O-bound work (fetching), a worker usually does not help unless you also do heavy processing on the results.
Common pitfalls interviewers look for
- Forgetting that workers cannot touch the DOM.
- Copying large payloads instead of using Transferables.
- Spawning too many workers (startup + memory cost).
- Not terminating workers or handling errors.
- Assuming every API is available inside a worker (environment-dependent).