Web Workers
An API that enables executing JavaScript in background threads. The worker thread can perform tasks without interfering with the user interface.
When to Use
- Parsing or manipulating massive JSON datasets.
- Client-side image processing, video encoding, or audio manipulation.
- Complex mathematical calculations (e.g. cryptography, physics engines).
- Formatting large rich-text documents.
When NOT to Use
- When the task involves manipulating the DOM directly.
- When the overhead of serializing/deserializing data via postMessage exceeds the cost of just running the task on the main thread.
- For simple UI state updates.
Advantages vs Limitations
Advantages
- Keeps the Main Thread completely free, ensuring 60fps animations and immediate user interaction regardless of workload.
- Supports fetching resources via XMLHttpRequest or fetch natively.
- Can utilize multi-core processors effectively in the browser.
Limitations
- Absolutely zero access to the DOM or the window object.
- Data passed between the main thread and workers must be copied (Structured Clone Algorithm), which can be slow for massive objects unless using Transferable Objects.
- Harder to debug and coordinate state across threads.
Production Examples
Offloading Heavy Processing
The heavyCalculation function completely freezes the worker thread, but the main thread remains untouched. The UI remains perfectly responsive.
// main.js
const worker = new Worker('worker.js');
worker.postMessage({ type: 'PROCESS_DATA', payload: massiveArray });
worker.onmessage = (e) => {
console.log('Processed data received:', e.data);
};
// worker.js
self.onmessage = (e) => {
if (e.data.type === 'PROCESS_DATA') {
const result = heavyCalculation(e.data.payload);
self.postMessage(result);
}
};Interview Readiness
Q: What is the cost of using postMessage to send a 50MB JSON object to a Web Worker, and how can it be optimized?
A: By default, postMessage uses the Structured Clone algorithm, which synchronously copies the 50MB object on the main thread, causing jank. To optimize, you can convert the data into an ArrayBuffer and pass it as a Transferable Object, which transfers ownership to the worker with zero-copy overhead.
Related Knowledge
Recommended Recipes
Heavy Background Processing
JavaScript is single-threaded by default. If a function takes 500ms to calculate a physics simulation, filter a 100,000-row array, or parse a 50MB JSON payload, the entire browser tab freezes for 500ms. Clicks, scrolls, and animations completely stop.
Preventing Memory Leaks from Event Listeners
In single-page applications, components mount and unmount repeatedly. If a component attaches a global event listener (on window, document, or a shared emitter) but never removes it on unmount, the listener and its closure — including references to the entire component tree — persist in memory indefinitely. Over time, this causes memory to grow without bound.