Web Workers Explained for Frontend Developers
Web Workers Explained for Frontend Developers
JavaScript in the browser is single-threaded โ but modern web apps often need to do heavy work without freezing the UI.
Thatโs where Web Workers come in.
Web Workers allow real parallel execution of JavaScript code in the browser.
๐ง The Problem Web Workers Solve
Without workers, heavy computations block the main thread:
button.onclick = () => {
heavyCalculation(); // โ UI freezes
};
Symptoms:
- Scrolling jank
- Input lag
- โPage is unresponsiveโ warnings
Why? ๐ The main thread is responsible for:
- Rendering
- User input
- Running JS
Block it, and everything stops.
๐ What Is a Web Worker?
A Web Worker is:
- A separate JavaScript thread
- Running in parallel to the main thread
- With its own event loop
- No access to the DOM
This is true parallelism, not just async I/O.
๐งฑ Main Thread vs Worker
| Capability | Main Thread | Web Worker |
|---|---|---|
| Run JS | โ | โ |
| DOM access | โ | โ |
| Parallel execution | โ | โ |
| Network requests | โ | โ |
| Timers | โ | โ |
| Blocking UI | โ | โ (isolated) |
โ๏ธ Basic Example
worker.js
self.onmessage = (event) => {
const result = event.data * 2;
self.postMessage(result);
};
main.js
const worker = new Worker("worker.js");
worker.postMessage(10);
worker.onmessage = (event) => {
console.log("Result from worker:", event.data);
};
Flow:
Main Thread โ postMessage โ Worker
Worker โ postMessage โ Main Thread
๐ Communication Model
Workers communicate via message passing, not shared memory (by default).
- Data is copied using the structured clone algorithm
- No race conditions
- No shared mutable state
worker.postMessage({ numbers: [1, 2, 3] });
โก Transferable Objects (Advanced)
To avoid copying large data:
worker.postMessage(buffer, [buffer]);
- Ownership transfers to the worker
- Zero-copy
- Original buffer becomes unusable on main thread
Great for:
- Image processing
- Audio buffers
- Large datasets
๐งฉ Real-World Use Cases
โ CPU-heavy work:
- Data processing
- Encryption / hashing
- Image resizing
- PDF parsing
- Chart calculations
โ Not for:
- DOM updates
- Simple async calls
- Lightweight logic
โ๏ธ Using Web Workers with React
useEffect(() => {
const worker = new Worker(new URL("./worker.js", import.meta.url));
worker.postMessage(data);
worker.onmessage = (e) => {
setResult(e.data);
};
return () => worker.terminate();
}, []);
Best practice:
- Create workers lazily
- Terminate when not needed
- Keep worker logic pure
๐ง Web Workers vs async/await
| Feature | async/await | Web Worker |
|---|---|---|
| Parallel JS | โ | โ |
| I/O concurrency | โ | โ |
| CPU offloading | โ | โ |
| DOM access | โ | โ |
๐งช Types of Workers
| Type | Description |
|---|---|
| Dedicated Worker | One page โ one worker |
| Shared Worker | Multiple tabs share |
| Service Worker | Network proxy / offline |
This article focuses on Dedicated Workers.
โ ๏ธ Common Mistakes
โ Doing DOM work in workers
โ Spawning too many workers
โ Sending huge objects without transferables
โ Forgetting to terminate workers
๐ง Mental Model
- Main thread = UI brain
- Worker = background CPU
- Messages = mailbox
Workers do the heavy lifting. Main thread stays smooth.
โ Summary
| Concept | Meaning |
|---|---|
| Web Worker | Background JS thread |
| Parallelism | Real CPU parallel execution |
| Communication | postMessage |
| DOM access | Not allowed |
| Best use | Heavy computation |
โจ Final Takeaway
If async/await gives you concurrency, Web Workers give you parallelism.
Use them when performance truly matters.
Suggested follow-ups
- SharedArrayBuffer & Atomics
- Worker Pools
- OffscreenCanvas