awesome-everything RU
↑ Back to the climb

Browser & Frontend Runtime

Workers: build a responsive offload pipeline

Crux Hands-on project — build a browser app that offloads heavy compute to a pooled worker over transferables, caches its shell in a recoverable service worker, and prove every claim with measured before/after numbers.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 240 min

Reading about workers is not the same as keeping a page at 60 fps while it grinds through real work. Build a small app that offloads a heavy job to a pooled worker, moves the data without a clone tax, and caches its shell behind a service worker you can actually recover from — proving each claim with measurements, not assertions.

Goal

Turn the unit’s mental model into a working pipeline: move heavy compute off the main thread, transfer the data instead of cloning it, bound the work with a pool and backpressure, and add a service worker for instant repeat loads that you can roll back when it breaks — all verified with before/after numbers.

Project
0 of 7
Objective

Build a browser app with one genuinely heavy operation (image filter, large-CSV/JSON parse-and-aggregate, or hashing) that stays at 60 fps under repeated triggering, moving data across the worker boundary without a structured-clone tax, and serving its shell from a recoverable service worker — proving responsiveness and transfer savings with measurements.

Requirements
Acceptance criteria
  • A before/after table: main-thread long-task duration, frames dropped during the operation, and sender-side postMessage block time — measured under the same trigger, by-value vs transfer, main-thread vs pooled worker.
  • A DevTools Performance trace at sustained load showing the main thread doing only UI work (no long tasks from the heavy operation) and the worker thread carrying the compute.
  • Under a rapid burst of triggers, the active-worker count and tab memory stay bounded — backpressure visibly rejects or drops excess work rather than spawning unbounded workers.
  • A repeat visit loads the shell instantly from cache, and the kill switch is shown detaching a broken service worker from a client without manual site-data clearing.
  • A one-paragraph write-up naming which transport you used for the payload (clone, transfer, or SAB) and why, and why the bottleneck was offloadable in the first place.
Senior stretch
  • Render the result with OffscreenCanvas: transfer a canvas to a render worker and draw the output (2D or WebGL) off the main thread; confirm the main thread shows zero rendering work for it in a trace.
  • Add a multithreaded-WASM codec or hasher behind cross-origin isolation: ship COOP: same-origin + COEP: require-corp (audited via report-only first), confirm self.crossOriginIsolated is true, and use a SharedArrayBuffer with Atomics to coordinate producer/consumer between threads.
  • Wrap the worker pool with Comlink and show that a coarse batch API beats a chatty per-item API in a tight loop — measure the task-hop cost of each.
  • Add an on-call runbook: how to read worker telemetry, detect a leaked worker (DevTools Performance → Threads), recognise version skew, and trigger the kill switch.
Recap

This is the loop you will run on every real worker problem: confirm the bottleneck is offloadable compute (not DOM mutation), move it to a pooled worker, transfer the data instead of cloning it, bound the work with backpressure, and cache the shell behind a service worker you can recover with a kill switch — verifying each step with before/after traces and numbers under identical load. Doing it once on a small app makes the production version muscle memory.

Continue the climb ↑What the reconciler does: render vs commit
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.