Жизненный цикл: install, activate, fetch

Урок разбирает жизненный цикл Service Worker по событиям install, activate и fetch.

Жизненный цикл Service Worker — последовательность состояний (installing → installed → activating → activated), через которые проходит Service Worker от регистрации до полноценной работы.

Три ключевых события

Код Service Worker строится вокруг трёх событий:

  • install — срабатывает один раз при установке. Здесь обычно кешируют статические ассеты (App Shell).
  • activate — срабатывает, когда Service Worker становится активным. Здесь чистят старые кеши.
  • fetch — срабатывает на каждый сетевой запрос. Здесь решают, отдать из кеша или из сети.
register
   |
   v
 install  --> кешируем оболочку (caches.open + addAll)
   |
   v
 activate --> чистим старые кеши
   |
   v
 fetch    --> отвечаем из кеша или сети (на каждый запрос)

Событие install и waitUntil

const CACHE = 'app-v1';
self.addEventListener('install', function (event) {
  event.waitUntil(
    caches.open(CACHE).then(function (cache) {
      return cache.addAll(['/', '/styles.css', '/app.js', '/offline.html']);
    })
  );
});

Метод event.waitUntil(promise) говорит браузеру: «не считай установку завершённой, пока этот Promise не выполнится». Без него браузер мог бы посчитать Service Worker установленным до того, как кеш заполнится, и при первом офлайне ассетов не оказалось бы.

Событие activate

self.addEventListener('activate', function (event) {
  event.waitUntil(
    caches.keys().then(function (names) {
      return Promise.all(
        names.filter(function (n) { return n !== CACHE; })
             .map(function (n) { return caches.delete(n); })
      );
    })
  );
});

На activate удобно удалять кеши предыдущих версий, чтобы не копить мусор. Когда вы выпускаете новую версию приложения, вы меняете имя кеша (app-v1app-v2), и старый кеш здесь подчищается.

skipWaiting и clients.claim

Есть два механизма ускорить вступление нового Service Worker в строй:

  • self.skipWaiting() в install — новый Service Worker не ждёт, пока закроются все вкладки со старым, а активируется сразу.
  • clients.claim() в activate — новый Service Worker сразу берёт под контроль уже открытые вкладки, не дожидаясь их перезагрузки.

Вместе они позволяют новой версии заработать немедленно — но применять их надо осознанно (об этом в уроке про обновление SW).

Как работает под капотом состояние waiting

Когда вы обновили sw.js, браузер устанавливает новый Service Worker, но по умолчанию он переходит в состояние waiting и ждёт, пока закроются все вкладки со старой версией. Это сделано, чтобы не «дёргать» приложение под пользователем. Поэтому новая логика часто «не подхватывается» до полного закрытия и повторного открытия приложения — это не баг, а защитное поведение.

Частые ошибки

  • Забыть waitUntil. Установка завершится раньше, чем заполнится кеш, и офлайн не сработает на первой загрузке.
  • Не чистить старые кеши. Память сайта будет расти от версии к версии.
  • Удивляться, что новый SW не активен. Он в waiting, пока открыты старые вкладки.

Итоги

  • Три события: install (кешируем оболочку), activate (чистим старые кеши), fetch (отвечаем на запросы).
  • event.waitUntil() держит событие открытым до завершения Promise.
  • Новый Service Worker по умолчанию ждёт в waiting, пока закрыты старые вкладки.
  • skipWaiting + clients.claim позволяют активироваться немедленно.
Проверьте себя
1. На каком событии Service Worker обычно кешируют App Shell?
Afetch
Binstall
Cactivate
Dpush
2. Зачем нужен event.waitUntil() в обработчике install?
AЧтобы ускорить установку
BЧтобы браузер не считал установку завершённой, пока не выполнится переданный Promise (кеш не заполнится)
CЧтобы отключить кеш
DЧтобы перехватывать fetch
3. Почему новая версия Service Worker не всегда активируется сразу?
AИз-за ошибки в коде
BПо умолчанию новый SW ждёт в состоянии waiting, пока открыты вкладки со старой версией
CБраузер не поддерживает обновления
DНужно переустановить приложение