Skip to main content
Support

Browse by category

All categories
← All posts
Deep dive May 15, 2026 · 4 min read

Web Workers explained without code

A Web Worker is a second thread the browser gives a webpage so heavy work does not freeze the interface. It is one of the two browser features that make local-first PDF tools possible. Here is what it does, why it matters, and how to spot one in DevTools.

By Khine 758 words Extractable lead
Web Workers explained without code — hero illustration

§1 — Problem statement

A webpage’s main thread does two jobs at once: it runs the page’s JavaScript and it keeps the UI responsive (scrolling, clicks, animations, the cursor blinking in a text input). When the main thread is busy doing heavy work — compressing a 50 MB PDF, encoding a video, running OCR on a scanned document — it can’t also respond to user input. The page freezes. The fan spins. The “page unresponsive” warning appears.

Web Workers solve this by giving the page a second thread.

§2 — Definition

A Web Worker is a JavaScript file the browser runs in a separate thread of execution, parallel to the page’s main thread. The worker can do heavy computation; the main thread stays responsive. The two communicate via message-passing.

Workers and the page each have their own scope — they don’t share variables directly, only messages. This pattern is sometimes called “shared-nothing parallelism.” Less elegant than threads in a native app, but safer and good enough for the workloads browsers care about.

§3 — Loft’s Worker usage

Several heavy tools delegate work to dedicated Workers:

§3.1 — Deskew worker

A dedicated deskew worker runs the deskewing math off the main thread so deskewing a multi-page PDF doesn’t freeze the UI.

§3.2 — Gerber parse worker

A dedicated parser worker handles Gerber files — Gerber syntax is verbose and the parse-into-geometry step can take seconds on complex boards. A thin main-thread facade coordinates the message exchange and hands results back to the viewer.

§3.3 — Background-removal worker

A dedicated background-removal worker runs the ONNX inference off the main thread. The model is heavy and would otherwise freeze the page for several seconds. A main-thread client coordinates the handoff.

§3.4 — Shared worker-bus

A shared worker-bus abstraction sits over message-passing so different tools can share a consistent worker pattern.

§4 — Verification

What to checkWhere in DevTools
Active workers and their stateSources tab → Threads panel
Worker source filesSources tab → file tree
Worker call frames during executionPerformance tab → recording timeline
Worker storage / IndexedDB accessApplication tab
Worker network requestsNetwork tab (request initiator column)

You can also pause individual workers and inspect their state independently from the main thread.

§5 — Why this matters for local-first

Server-side tools didn’t need workers because the heavy work happened elsewhere. The browser’s job was just to show a progress spinner while the upload finished. Once the work moves to the browser, you immediately need a way to keep the interface responsive. Without Web Workers, every local tool would feel like the page hung every time it processed anything.

Workers and WebAssembly are the matched pair. WASM gives the browser the speed of native code; Workers give the page somewhere safe to run that code without breaking the UI. Either alone wouldn’t be enough.

§6 — Constraints

ConstraintDetail
DOM access from workernone. Worker can compute anything but cannot manipulate the page. Must postMessage results back to main thread.
Message-passing overheadsmall (~few ms for typical payloads), larger for big binary data. Mitigation: Transferable objects pass ownership instead of copying.
Workers per pageuncapped but mobile browsers throttle aggressively. Loft uses a handful per tool, not hundreds.
Lifetimeworkers can be terminated by the browser when idle. They wake up when a controlled page sends a message.
Module workersnewer; modern stack uses them. Some older patterns still use classic workers via importScripts.

§7 — Open questions

  • Shared workers across tabs. Useful for cross-tab coordination but underused outside of multi-tab apps. Loft doesn’t use them today.
  • Worker debugging UX. DevTools support has improved but is still less polished than main-thread debugging. The flame-graph view in particular sometimes mislabels worker frames as “(anonymous).”

§8 — References

Anyway — workers don’t get the same blog-post energy as WASM, but they do half the lifting. The reason the page doesn’t freeze when you compress a 50 MB PDF isn’t WASM speed; it’s the worker keeping the main thread free. Worth crediting where credit is due.

References

  1. Web Workers API — MDN Web Docs — Mozilla (accessed 2026-05-27)