Lesson 0003 · ~10 minutes

The update dance

One skill: explain why a new service worker often waits, when skipWaiting is worth it, and how two versions coexist without trash-compacting each other’s caches.

Win (do this, then stop)

Finish the 4 quiz cards. You should be able to say: “New SW installs beside the old one, waits until no clients, then activates — unless we skipWaiting.”

You already know (lesson 2)

1. The pain this solves

You shipped a fix. User still sees the bug. Three common reasons:

  1. New SW is waiting (old one still owns open tabs).
  2. Refresh didn’t free the old SW (navigation overlap keeps a client alive).
  3. You changed the SW filename and the old SW never loads the new HTML that points at it.

Source of truth: Jake Archibald — lifecycle (Updating section).

2. Default update path (memorize this order)

1. Check

Browser re-fetches the same script URL (e.g. /sw.js) on navigation (and other triggers).

2. Diff

Bytes different → this is a new worker. Same URL on purpose — do not ship sw-v2.js as your update strategy.

3. Install

New worker runs install while old is still active. Precache into a new cache name (static-v2.

4. Wait

New worker sits in waiting until the old one controls zero clients.

5. Activate

Old gone → activate. Delete obsolete caches here. Then new navigations use the new SW.

Refresh trap

One tab + refresh often keeps the old SW in control during the navigation. Closing all tabs (or waiting for zero clients) is what unblocks waiting — unless you skipWaiting.

3. Two knobs people mix up

Knob Does Use when
skipWaiting() New SW activates as soon as install finishes (skips waiting) Safe to mix old page + new fetch handler, or user clicked “Update”
clients.claim() Active SW takes over pages that weren’t controlled yet First-visit / uncontrolled tabs need SW fetch ASAP
// common pattern — not free magic; know the risk
self.addEventListener("install", (event) => {
  self.skipWaiting();
  event.waitUntil(
    caches.open("static-v2").then((c) => c.addAll(["/", "/app.js"]))
  );
});

Risk of skipWaiting: a page loaded under the old SW suddenly gets later requests from the new SW. Fine for many static apps; dangerous if HTML and API contracts diverge between versions (lifecycle caution).

4. Cache names = version safety

  1. Install: open static-v2, fill it.
  2. Leave static-v1 alone while old SW still runs.
  3. Activate: delete cache names you no longer expect.

That is how two versions coexist without one deleting the other’s offline shell mid-session.

5. Quiz (4 cards — your only required action)

1 of 4

Old SW is active. New /sw.js bytes differ and install succeeds. What is the new worker’s default next state?

2 of 4

User has one tab open. They refresh after deploy. New SW is still “waiting.” Best default explanation?

3 of 4

Product wants the new SW active as soon as install finishes, even with tabs open. Which API?

4 of 4

Old SW still uses cache static-v1. New SW should precache safely. Best pattern?

6. Keep these four lines

  1. Same SW URL; bytes change = new version.
  2. New installs beside old → then waits.
  3. skipWaiting trades safety for speed.
  4. New cache name on install; delete old on activate.
Ask your teacher Stuck on “waiting forever,” Workbox’s update UX, or controllerchange reload patterns — ask in chat (one question is enough).

Primary (optional, ~10 min)

Lifecycle → Updating only. You can skip the first-SW half if lesson 2 already stuck.