Skip to content

Web Workers & SharedWorker

JavaScript is single-threaded. Every script, DOM update, layout calculation, and event handler runs on one thread. When you run a long computation — parsing a large file, computing a hash, processing an image — the entire UI freezes for the duration. Scroll events stop firing, animations stutter, and clicks go unanswered.

Web Workers let you move heavy work to a background thread. The browser creates a separate JS environment with its own event loop. The main thread and the worker communicate by sending messages with postMessage and receiving them via onmessage. The two threads never share memory by default, so there are no race conditions.

flowchart LR
  MT["Main Thread
(UI, events)"]
  DW["Dedicated Worker
(background JS)"]
  MT -- "worker.postMessage(data)" --> DW
  DW -- "self.postMessage(result)" --> MT
Main thread ↔ Dedicated Worker via postMessage/onmessage
Dedicated WorkerSharedWorker
ScopeOne tab / one scriptAll tabs of the same origin
Constructornew Worker(url)new SharedWorker(url)
MessagingDirect: worker.postMessage(data)Via MessagePort: port.postMessage(data)
Worker sideself.onmessage = fnMust handle onconnect first, then listen on event.ports[0]
ComplexitySimpleModerate — requires port bookkeeping
Use caseCPU-heavy task in one tabShared cache, cross-tab coordination
LessonWhat you learn
index (this page)Overview, dedicated vs shared, module map
web-workersCreate, message, and terminate a Dedicated Worker
postmessage-and-transferablesStructured clone vs zero-copy transferables
sharedworkerConnect multiple tabs to one SharedWorker
worker-patternsError handling, worker pools, and best practices

The snippet below creates a Dedicated Worker via a Blob URL, sends the number 10, and the worker computes Fibonacci off-thread and posts back the result.

Browser Storage
What is the main reason to move work to a Web Worker?
Which worker type is shared across all tabs of the same origin?
How do the main thread and a worker communicate?