JavaScript is single-threaded on the main thread — a heavy computation blocks the entire UI, including scrolling and clicks. Web Workers run JavaScript on a genuinely separate thread to avoid exactly that.
// worker.js - runs on a separate thread, no DOM access
self.onmessage = (e) => {
const result = heavyComputation(e.data);
self.postMessage(result);
};
function heavyComputation(n) {
let total = 0;
for (let i = 0; i < n; i++) total += Math.sqrt(i);
return total;
}
const worker = new Worker('worker.js');
worker.postMessage(100_000_000); // main thread stays responsive during this
worker.onmessage = (e) => {
console.log('Result:', e.data);
};
Workers communicate with the main thread only via message passing (postMessage) — they can’t touch the DOM directly, which is the trade-off for genuine parallelism: real isolation instead of shared mutable state, avoiding the classic threading bugs found in languages with true shared-memory threads.