Web Worker (and the offload boundary)
A Web Worker runs JavaScript on a separate thread from the main thread, so heavy work can run without blocking rendering or input. It’s the standard tool for keeping the main thread responsive. The catch, per when-to-block-main-thread, is that the boundary between threads is not free — and understanding its cost is what tells you when offloading actually pays.
Shared-nothing, so everything is a message
Workers (and their relatives — service workers, Chrome-extension background/offscreen contexts) are
shared-nothing: they can’t read each other’s memory. They communicate by postMessage(), and by default
the payload is copied with the Structured Clone Algorithm (SCA) — a synchronous, blocking, O(n) deep
copy on the sending side (and a deserialize on the other). For small messages this is invisible; for a
multi-megabyte payload (image pixel data) the clone can cost more than the work being offloaded, so the
offload is a net loss.
Transferable objects — ownership handoff instead of copying
The way around the copy is transferable objects: ArrayBuffer, ImageBitmap, and MessagePort can be
transferred, handing the receiving context ownership of the underlying memory rather than duplicating
it (near zero-copy). Chrome’s benchmark cited in when-to-block-main-thread: a 32 MB payload moves in
7 ms transferred vs ~300 ms cloned — about 43×. The trade-offs:
- The sender loses access to the object after transfer (ownership moved).
- Only a few types qualify as transferable.
- Some contexts (Chrome extension messaging) force JSON serialization, so transferables aren’t available there at all.
When to offload vs keep on the main thread
The boundary cost is why when-to-block-main-thread‘s split matters: CPU-bound work (computation
dominates) should go to a worker — transfer is negligible next to the processing. Data-bound work (big
payload, light processing) should stay on the main thread — the copy costs more than the
work. Decide with a measurement (performance.mark/measure), not a reflex.
Related
main-thread · when-to-block-main-thread · inp · web-performance