๐Ÿณ IntuitiveFE
Login
โ† All concepts

Service Workers & Cache API

โฑ๏ธ ~3-minute bite ยท solve the sandbox to master

0%lesson
๐Ÿง’

5-Year-Old Metaphor

โ€” The physical, real-world picture. No jargon.

๐Ÿ•ต๏ธ A Service Worker is a personal proxy running in your browser.

The proxy analogy

Every network request your page makes goes through the Service Worker first โ€” like mail going through a proxy server. The SW can intercept (serve from cache), modify (add auth headers), queue (save for retry when offline), or forward (pass through to network).

It lives in a separate thread โ€” not the main JS thread. It keeps running even after the user closes your tab (briefly), which is how push notifications and background sync work.

What Service Workers unlock

๐Ÿ“ฆ Offline support

Serve cached assets when network fails. PWA apps work without internet.

โšก Performance

Cache-first assets load in 0ms. No network round trip for repeat visitors.

๐Ÿ“ถ Background sync

Queue failed requests. Retry automatically when connection returns.

๐Ÿ”” Push notifications

Receive server pushes and show OS-level notifications even when app is closed.

Critical constraints

  • โ€ข HTTPS only (localhost exempted for dev)
  • โ€ข Runs in separate thread โ€” no DOM access
  • โ€ข Scope-limited: /admin/sw.js can only control /admin/* pages
  • โ€ข Different from Web Worker (SW intercepts network; Web Worker runs compute)
๐ŸŽ›๏ธ

Interactive Sandbox

โ€” Move something, see it react instantly.

Pattern

Scope:/ (all pages)
register()

navigator.serviceWorker.register('/sw.js')

Browser downloads and parses sw.js

install

self.addEventListener('install', e => e.waitUntil(precache()))

SW caches core assets (precache)

waiting

New SW waits โ€” old SW still active

New SW in waiting state

activate

self.addEventListener('activate', e => e.waitUntil(cleanOldCaches()))

Old SW deactivated, new SW takes control

skipWaiting + clients.claim()

self.skipWaiting(); self.clients.claim()

New SW immediately takes control of all pages

Step 1/5: Page calls register(). Browser downloads sw.js if not already installed. The SW file is checked for byte changes โ€” even one byte triggers a new SW install.
1 / 5
โš ๏ธ Gotcha: After deploying a new SW, users with open tabs won't get it until they close all tabs and reopen. skipWaiting() forces immediate activation but risks inconsistency between old HTML + new SW. Always test the update flow.
๐Ÿ’ก Insight: The byte-check update mechanism means updating sw.js content triggers reinstall. A common pattern: keep sw.js as a tiny file that imports the actual logic, or use a version hash comment in sw.js to force updates.
Completed:๐Ÿ”„๐Ÿ”๐Ÿ“ฆ๐Ÿ“ถ๐Ÿ””
๐ŸŽฏ

Challenge

Step through all 5 patterns to their final step. Understand the SW lifecycle and cache strategies.

Try it
๐ŸŽฏ

Why Should I Care?

โ€” The exact interview question + the bug it kills.

Interview questions

Q: Why can Service Workers only work on HTTPS?

A SW sits between your page and the network โ€” it can intercept and modify any request. On HTTP, an attacker with network access could inject a malicious SW that intercepts all your traffic. HTTPS prevents this: the SW file is delivered over an authenticated, encrypted connection, so you know it's your code running. Exception: localhost is allowed without HTTPS for development purposes.

Q: What is the difference between Service Worker and Web Worker?

Both run in separate threads (no DOM access, communicate via postMessage). The difference: Web Workers are for offloading CPU-intensive computation (image processing, data parsing) โ€” they live only while the page is open. Service Workersare a network proxy โ€” they intercept fetch requests, manage caches, and can run briefly after the tab closes (for push and background sync).

Q: How do you handle SW updates without breaking users?

The safest pattern: let the new SW wait (default behavior). Show a "New version available โ€” click to update" banner when a waiting SW is detected via registration.waiting. When the user clicks, send the waiting SW a SKIP_WAITING postMessage, then window.location.reload() to load the new version. This gives users control and prevents mid-session breakage.

๐Ÿ”ฌ

The Deep Dive

โ€” Spec refs, engine internals, the minutiae.

Workbox โ€” production cache management

Writing cache strategies manually is error-prone. Workbox (Google) provides battle-tested implementations:

js
1import { registerRoute } from 'workbox-routing';
2import { StaleWhileRevalidate, CacheFirst, NetworkFirst } from 'workbox-strategies';
3import { CacheableResponsePlugin } from 'workbox-cacheable-response';
4ย 
5// Static assets: cache first, max 30 days
6registerRoute(
7 ({ request }) => request.destination === 'image',
8 new CacheFirst({ cacheName: 'images', plugins: [
9 new CacheableResponsePlugin({ statuses: [0, 200] }),
10 ]}),
11);
12ย 
13// API: network first, fall back to cache
14registerRoute(
15 ({ url }) => url.pathname.startsWith('/api/'),
16 new NetworkFirst({ cacheName: 'api-responses' }),
17);
18ย 
19// App shell: stale-while-revalidate
20registerRoute(
21 ({ request }) => request.mode === 'navigate',
22 new StaleWhileRevalidate({ cacheName: 'pages' }),
23);

SW debugging in Chrome DevTools

Application โ†’ Service WorkersSee registered SWs, status (activated/waiting), force update, unregister
Application โ†’ Cache StorageBrowse all caches, see cached URLs and responses
Network tab: throttle to OfflineTest offline fallback behavior
Application โ†’ Background SyncTrigger sync events manually without waiting for connectivity

SW update patterns comparison

PatternWhen activatesRisk
Default waitAfter all old-SW tabs closedLow โ€” safest
skipWaiting (auto)Immediately on installOld HTML + new SW mismatch
User-triggered skipUser clicks 'Update now'Low โ€” user controls timing
๐ŸŽค

Interview Questions

โ€” Real questions from real interviews โ€” with answers.

Install โ†’ precache; waiting โ†’ new SW pauses until all old-SW tabs close; activate โ†’ clean old caches and take control.

Serve the cached version immediately while fetching a fresh copy in the background for the next request.

Responses are single-use streams โ€” reading the body for caching consumes it; clone() gives you two independent readable copies.

Background Sync fires even after the user closes the app; a JS retry loop stops when the tab closes.

HTTPS is required (except localhost) because a SW intercepts all requests โ€” on HTTP an attacker could inject a malicious SW.

Detect registration.waiting, show an update banner, send SKIP_WAITING on user click, then reload.

๐ŸŽฎ

Memory Game

โ€” Quick quiz โ€” lock the concept in long-term memory.
1/4

What is the purpose of `clients.claim()` in the `activate` event?