Skip to main content
Progressive Web Apps·Lesson 2 of 5

Service Workers

Service workers are the engine behind Progressive Web Apps. They are JavaScript files that run in a separate thread from your web page, acting as a programmable network proxy between your app and the server.

How Service Workers Differ from Regular JavaScript

PropertyWeb Page JSService Worker
ThreadMain threadSeparate background thread
DOM accessYesNo
LifecycleTied to pageIndependent of page
Network accessDirectIntercepts all requests
HTTPS requiredNoYes (except localhost)
Persistent storagelocalStorage, IndexedDBCache API, IndexedDB

Registration

Register the service worker from your main JavaScript file:

Ctrl+Enter
HTML
CSS
JS
Preview

Scope

The scope determines which pages the service worker controls. By default, it is the directory where sw.js lives.

Ctrl+Enter
HTML
CSS
JS
Preview

The Install Event

The install event fires when the browser detects a new or updated service worker. This is where you pre-cache your app shell.

Ctrl+Enter
HTML
CSS
JS
Preview

event.waitUntil() tells the browser to keep the service worker alive until the promise resolves. If the promise rejects, the installation fails.

The Activate Event

The activate event fires after installation, when the service worker takes control. Use this to clean up old caches.

Ctrl+Enter
HTML
CSS
JS
Preview

skipWaiting and clients.claim

By default, a new service worker waits until all tabs using the old one are closed. These methods bypass that:

  • self.skipWaiting() — activates the new worker immediately
  • self.clients.claim() — takes control of all open pages without a reload

The Fetch Event

This is where the magic happens. The service worker intercepts every network request from controlled pages.

Ctrl+Enter
HTML
CSS
JS
Preview

Why clone the response?

A response body can only be read once. If you want to cache the response and also return it to the page, you must clone it:

const response = await fetch(request);
cache.put(request, response.clone()); // clone for cache
return response;                       // original for page

The Cache API

The Cache API stores request-response pairs.

Ctrl+Enter
HTML
CSS
JS
Preview

Updating Service Workers

When you change your sw.js file (even one byte), the browser treats it as a new version.

Update Flow

  1. Browser fetches sw.js and detects changes
  2. New service worker installs alongside the old one
  3. New worker enters "waiting" state
  4. When all tabs using the old worker close, the new one activates

Versioned Caches

Use version numbers in cache names so the activate event can clean up old caches:

Ctrl+Enter
HTML
CSS
JS
Preview

Communicating with the Page

Service workers and pages can exchange messages:

Page to Service Worker

Ctrl+Enter
HTML
CSS
JS
Preview

Service Worker to Page

Ctrl+Enter
HTML
CSS
JS
Preview

Debugging Service Workers

Use Chrome DevTools:

  1. Open Application tab
  2. Click Service Workers in the sidebar
  3. See registered workers, their state, and controls to:
    • Update — force check for a new version
    • Unregister — remove the service worker
    • skipWaiting — activate a waiting worker

Check Cache Storage to see what is cached and Network tab to see which requests the service worker intercepted.

Practical Exercise

Build a service worker with proper versioning and cleanup:

Ctrl+Enter
HTML
CSS
JS
Preview

Key Takeaways

  • Service workers run in a background thread with no DOM access but full control over network requests.
  • The lifecycle (install, activate, fetch) gives you precise control over caching and updates.
  • Always clone responses before caching — a response body can only be consumed once.
  • Use versioned cache names and clean up old caches during activation.
  • skipWaiting() and clients.claim() let new service workers take over immediately.