BitlystBitlyst
PostsSeriesTopicsAbout

Bitlyst

Short, diagram-first posts on JavaScript, React & Next.js. Follow via RSS or the newsletter.

ยฉ 2026 Mohsen Fallahnejad

PostsSeriesTopicsLinksAboutRSSGitHubX
Posts/javascript
Intermediate3 min read

Web Workers Explained for Frontend Developers

How Web Workers work, why they matter, and when to use them to achieve real parallelism in frontend apps.

Mohsen Fallahnejad

Mohsen Fallahnejad

Dec 30, 20252 readsDiscuss

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:

js
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#

CapabilityMain ThreadWeb Worker
Run JSโœ…โœ…
DOM accessโœ…โŒ
Parallel executionโŒโœ…
Network requestsโœ…โœ…
Timersโœ…โœ…
Blocking UIโŒโŒ (isolated)

โš™๏ธ Basic Example#

worker.js#

js
self.onmessage = (event) => {
  const result = event.data * 2;
  self.postMessage(result);
};

main.js#

js
const worker = new Worker("worker.js");

worker.postMessage(10);

worker.onmessage = (event) => {
  console.log("Result from worker:", event.data);
};

Flow:

  1. 1

    Main Thread

  2. 2

    postMessage

  3. 3

    Worker

then
Worker responds
  1. โ†ณpostMessage
  2. โ†’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
js
worker.postMessage({ numbers: [1, 2, 3] });

โšก Transferable Objects (Advanced)#

To avoid copying large data:

js
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#

tsx
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#

Featureasync/awaitWeb Worker
Parallel JSโŒโœ…
I/O concurrencyโœ…โœ…
CPU offloadingโŒโœ…
DOM accessโœ…โŒ

๐Ÿงช Types of Workers#

TypeDescription
Dedicated WorkerOne page โ†” one worker
Shared WorkerMultiple tabs share
Service WorkerNetwork 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#

ConceptMeaning
Web WorkerBackground JS thread
ParallelismReal CPU parallel execution
CommunicationpostMessage
DOM accessNot allowed
Best useHeavy 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
Filed under#javascript#web workers#performance#parallelism#browser

Was this worth your time?

One tap tells me what to write more of.

Mohsen Fallahnejad

Written by

Mohsen Fallahnejad

Frontend engineer explaining JavaScript, React & Next.js internals in posts you can finish over coffee. More about me

X โ†—GitHub โ†—LinkedIn โ†—
โ† OlderuseDeferredValue Explained: Keeping React UIs ResponsiveNewer โ†’Are TypeScript Enums a Good Idea? (Bundle Size & Runtime)

Start the discussion

Questions, corrections, a better approach? I read and reply to every comment.

Read next

Debounce vs Throttle โ€” One Sentence to Remember Forever

Two patterns for taming fast events: debounce waits for silence, throttle limits how often. With examples, code, and interview answers.

Jul 8, 20264 min read1

Microtask vs Macrotask in JavaScript โ€” With Node.js vs Browser Notes

Understand microtasks and macrotasks across browsers and Node.js, including process.nextTick, setImmediate, and event loop phases.

Sep 20, 20253 min read

The $4.35 Item That Was Charged $4.34

Why 0.1 + 0.2 !== 0.3 in JavaScript, how floating-point math drops a cent when converting dollars to cents, and why money should be stored as integers.

Nov 3, 20265 min read1

Get new posts in your inbox

No spam. Unsubscribe any time.

3 min left
Discuss๐Ÿ‘ React
๐Ÿ‘