Service Worker Lifecycle

A service worker moves through registration, installation, activation, and control phases. Understanding these transitions explains when lifecycle events run, when a worker can take control of pages, and why updates may require a reload.

A page starts the process by calling `navigator.serviceWorker.register()`. The browser downloads the service worker script and, if registration succeeds, creates or updates a worker associated with that registration. Registration does not immediately mean the worker controls the current page.

During installation, the browser creates a new worker and fires the `install` event. This phase is commonly used to pre-cache resources with `cache.addAll()` and `event.waitUntil()`. If the installation fails, the new worker is not activated.

After successful installation, the worker enters the waiting state when an older worker is still controlling clients. Once it is allowed to activate, the browser fires `activate`, where cleanup such as deleting obsolete caches is typically performed. `event.waitUntil()` can keep activation pending until asynchronous cleanup finishes.

After activation, the worker can control pages under its scope when those clients are controlled by that worker. A newly installed worker generally does not take control of an already-open page until that page is navigated or reloaded, unless the worker uses `self.skipWaiting()` and then claims clients with `self.clients.claim()`. These APIs change normal lifecycle timing, so they should be used deliberately.

Key points

Interview questions

What are the main stages of the service worker lifecycle?

The main stages are registration, installation, waiting when an older worker is active, activation, and control of clients. Registration creates or updates the registration. Installation is where initial setup such as caching can happen, while activation is commonly used for cleanup. Control begins when the active worker is associated with eligible pages under its scope.

What is the purpose of `event.waitUntil()` in a service worker lifecycle event?

`event.waitUntil()` tells the browser that asynchronous work associated with an extendable lifecycle event must complete before the event is considered successful. For installation, this is important when resources must be cached before the worker can proceed. For activation, it can keep cleanup work from being cut short. If the supplied promise rejects, the lifecycle operation can fail.

Why doesn't a newly installed service worker immediately control the page that registered it?

The new worker normally becomes active only after the previous worker no longer needs to control its existing clients. Even after activation, an already-open page is not automatically controlled by the new worker merely because the worker is active. A navigation or reload normally establishes control. `skipWaiting()` and `clients.claim()` can alter these normal transitions.

Where would you put cache cleanup logic in a service worker?

Cache cleanup is normally placed in the `activate` event. A common approach is to inspect existing cache names and delete entries that do not belong to the current cache version. The asynchronous deletion should be passed to `event.waitUntil()` so activation waits for the cleanup. This helps prevent stale cache versions from accumulating.

What problem do `skipWaiting()` and `clients.claim()` solve, and what trade-off do they introduce?

They can shorten the time between installing an updated worker and having that worker control existing pages. `skipWaiting()` moves a waiting worker toward activation, while `clients.claim()` lets the active worker take control of matching existing clients. The trade-off is that an old page can suddenly be served by a new worker, potentially creating mismatches between page code and worker behavior. Updates therefore need compatible coordination between the page and worker.