Fossils🌐 Web PlatformWeb Workers & Service Workers Explained
ðŸĶ–DinosaurBrowserPerformanceWorkers

Web Workers & Service Workers Explained

JavaScript is single-threaded... except when it isn't. This question tests whether you know how to break free from the main thread.

Web Workers & Service Workers Explained

Interview Question: "What are Web Workers and Service Workers? When would you use each?"

The Senior Answer

"JavaScript is single-threaded — all UI rendering, event handling, and computation share one thread. Web Workers let you run JavaScript on a separate background thread for heavy computation without blocking the UI. Service Workers are a special type of worker that acts as a programmable network proxy — intercepting fetch requests, caching responses, and enabling offline functionality. They're different tools for different problems."

The Distinction

Web WorkerService Worker
PurposeOff-main-thread computationNetwork proxy, caching, offline
LifecycleLives as long as page is openPersists across page loads
Triggered bynew Worker() in your codeBrowser events (fetch, push, sync)
DOM accessNoNo
Network interceptionNoYes (fetch event)
Push notificationsNoYes
Shared across tabsNo (Shared Worker can)Yes (controls all tabs in scope)

Web Workers: When and How

When to Use

"Move work to a Web Worker when it's CPU-intensive and blocks the main thread for more than 50ms — the long task threshold. Common examples: sorting large datasets, parsing CSV/JSON files, image processing, search indexing, cryptographic operations."

Communication Pattern

// Main thread
const worker = new Worker('/heavy-work.js');
worker.postMessage({ type: 'SORT', data: thousandItems });
worker.onmessage = (e) => renderResults(e.data);
 
// Worker
self.onmessage = (e) => {
  const sorted = expensiveSort(e.data.data);
  self.postMessage(sorted);
};

Performance Optimization: Transferable Objects

"By default, postMessage copies data between threads. For large ArrayBuffers, use transfer instead — it moves ownership to the worker in O(1), regardless of size."

const buffer = new ArrayBuffer(100_000_000); // 100MB
worker.postMessage({ buffer }, [buffer]); // Transfer, not copy
// buffer.byteLength is now 0 in main thread (ownership transferred)

What Workers Can't Do

"Workers cannot access the DOM, document, or window. They can use fetch, IndexedDB, WebSocket, setTimeout, crypto, and importScripts. The constraint is intentional — DOM access from multiple threads would require locks and create deadlocks."

Service Workers: When and How

When to Use

"Service Workers are for offline functionality, intelligent caching, and background operations. They sit between your app and the network, intercepting every fetch request. Use them for PWAs, offline-first apps, or apps that need push notifications or background sync."

The Lifecycle

"Service Workers have a specific lifecycle that trips up most developers:

  1. Register — Your app tells the browser about the SW
  2. Install — SW downloads and caches critical assets
  3. Activate — SW takes control (can clean old caches)
  4. Idle — SW sleeps until an event wakes it (fetch, push, sync)
  5. Terminated — Browser kills idle SWs to save memory; they restart when needed"

Caching Strategies

"The strategy depends on the resource:

Cache First — Check cache, fallback to network. Best for static assets (CSS, JS, images) that rarely change.

Network First — Try network, fallback to cache. Best for API data where freshness matters but offline support is needed.

Stale While Revalidate — Serve from cache immediately (fast!), then update cache from network in the background. Best for semi-dynamic content."

Follow-Up Questions

"How do you update a Service Worker?"

"When the browser fetches the SW script and finds even one byte different, it installs the new version. But the new SW waits until all tabs using the old SW close. This prevents version mismatches. You can force immediate activation with self.skipWaiting() in the install event and clients.claim() in the activate event — but be careful, as this can cause inconsistencies if old tabs expect old behavior."

"Can you share state between a Worker and the main thread?"

"By default, no — communication is via message passing (postMessage). Data is copied, not shared. However, SharedArrayBuffer allows true shared memory between threads, but it requires cross-origin isolation headers (COOP and COEP) and is still relatively uncommon in web apps."

"What's a Shared Worker?"

"A Shared Worker is a single worker shared across all tabs of the same origin. It's useful for shared WebSocket connections, cross-tab state synchronization, or shared caching. Each tab connects via a MessagePort. They're less common than dedicated workers because BroadcastChannel and Service Workers cover most cross-tab needs."

"When is the overhead of Workers NOT worth it?"

"When the computation takes less than the message passing overhead (~1-5ms). For operations under 16ms (one frame), the overhead of serializing data, posting a message, and receiving the result can be more than just doing the work on the main thread. Workers shine when computation is 50ms+."

"How do Web Workers relate to React?"

"React doesn't use workers internally — reconciliation happens on the main thread (using time-slicing via Fiber instead of threading). But you can use workers alongside React for heavy computations — search indexing, data transformation, image processing — via custom hooks that wrap postMessage communication."

The Architecture Insight

"Workers are about isolating expensive work from user-visible operations. The main thread should be reserved for rendering and responding to input. Everything else — data processing, caching logic, background sync — can and should run elsewhere."

Red Flags

  • Confusing Web Workers with Service Workers
  • Thinking workers can access the DOM
  • Not knowing the Service Worker lifecycle (install → activate → fetch)
  • Missing the caching strategy dimension (cache-first vs network-first)
  • Saying "JavaScript can't do multithreading" (it can — via Workers)