What is a service worker and what can it do?
Take a moment.
Say your answer out loud or write it down first — retrieval is what makes it stick. Reveal when you're ready.
Short answer
A service worker is a background script the browser runs independently of pages, acting as a programmable network proxy: it intercepts fetches to serve cached responses offline, pushes notifications, and syncs in the background. It requires HTTPS, has no DOM access, and updates through a strict install → activate lifecycle.
Detailed explanation
Once registered, a service worker sits between your pages and the network for its scope. Its superpower is the fetch handler: decide per request whether to answer from the Cache API, go to network, or combine strategies — cache-first for versioned assets, network-first for HTML/API data, stale-while-revalidate for feeds that tolerate slight age. That plus precached app shells gives offline-capable apps: the page loads from cache with zero network. Beyond caching: Push API wakes it for notifications even with no tab open, and Background Sync retries failed submissions when connectivity returns. Constraints define correct usage: HTTPS only (localhost exempt), no DOM or synchronous storage access (it runs off-main-thread and may be killed anytime — keep handlers event-driven and fast), and the update model is explicit — a new worker installs alongside the old, waits until all tabs close (or skipWaiting), then activates and typically purges old caches. Debugging lives in DevTools' Application panel (inspect workers, simulate offline, clear storage). Cost to name: cache versioning bugs serve stale app shells — always version caches and clean up in activate.
Example
// Register once from your page
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
// sw.js — stale-while-revalidate for images
self.addEventListener('fetch', (event) => {
if (event.request.destination === 'image') {
event.respondWith(
caches.open('img-v1').then(async (cache) => {
const cached = await cache.match(event.request);
const network = fetch(event.request).then((res) => {
cache.put(event.request, res.clone());
return res;
});
return cached ?? network; // instant paint, refresh behind the scenes
}),
);
}
});Interview tip
Frame it as a programmable proxy first, then name the three cache strategies with what each suits. Mentioning the waiting-lifecycle gotcha shows you have shipped one, not just read about them.
Common mistakes
- Expecting DOM access or persistent global state inside the worker.
- Shipping unversioned caches that trap users on stale app shells.
- Forgetting HTTPS is required in production.