Жизненный цикл Service Worker

Service Worker — это отдельный скрипт, который браузер запускает в фоновом режиме, отделённо от веб-страницы. Он способен перехватывать сетевые запросы, управлять кэшированием ресурсов и обеспечивать работу приложения в оффлайн-режиме. Жизненный цикл Service Worker строго структурирован, что обеспечивает контроль над обновлением и управлением кэшем.

Service Worker проходит несколько ключевых стадий: регистрация, установка, активация и работа с запросами. Каждая из этих стадий имеет свои особенности и API-интерфейсы.


Регистрация Service Worker

Регистрация выполняется с помощью метода navigator.serviceWorker.register(). Этот метод принимает путь к файлу скрипта Service Worker и возвращает промис, который сигнализирует об успешной регистрации.

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
    .then(registration => {
      console.log('Service Worker зарегистрирован:', registration);
    })
    .catch(error => {
      console.error('Ошибка регистрации Service Worker:', error);
    });
}

Ключевые моменты:

  • Service Worker работает только на HTTPS или на localhost.
  • Регистрация не гарантирует немедленное управление страницей; управление может начаться после следующей загрузки или при явной активации нового Service Worker.

Стадия установки (Install)

На этапе установки Service Worker может кэшировать необходимые ресурсы. Событие install позволяет выполнить подготовку к работе приложения в оффлайн-режиме.

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open('app-cache-v1')
      .then(cache => {
        return cache.addAll([
          '/',
          '/index.html',
          '/styles.css',
          '/main.js',
          '/logo.png'
        ]);
      })
  );
});

Важные моменты:

  • Метод event.waitUntil() гарантирует, что установка Service Worker не будет завершена до успешного выполнения всех асинхронных операций.
  • Если кэширование ресурсов завершится с ошибкой, Service Worker не активируется.

Стадия активации (Activate)

После установки Service Worker переходит в стадию активации. Это событие используется для управления устаревшими кэшами и подготовки нового Service Worker к работе.

self.addEventListener('activate', event => {
  const cacheWhitelist = ['app-cache-v1'];
  
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (!cacheWhitelist.includes(cacheName)) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

Особенности:

  • Активный Service Worker начинает контролировать страницы, загруженные после его активации.
  • Использование белого списка кэшей позволяет избежать накопления устаревших данных.

Перехват запросов (Fetch)

После активации Service Worker может перехватывать сетевые запросы через событие fetch. Это основной механизм для реализации оффлайн-режима и стратегий кэширования.

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        return response || fetch(event.request);
      })
  );
});

Принципы работы:

  • caches.match() проверяет наличие запрашиваемого ресурса в кэше.
  • Если ресурс отсутствует, выполняется сетевой запрос через fetch().
  • Можно реализовать различные стратегии: cache-first, network-first, stale-while-revalidate.

Обновление Service Worker

Обновление Service Worker происходит, когда браузер обнаруживает изменения в скрипте при регистрации. Новый Service Worker устанавливается, но не активируется до закрытия всех контролируемых страниц. Это предотвращает внезапные изменения поведения приложения.

Стратегии обновления:

  • Wait until activation — новый Service Worker ожидает закрытия всех страниц.
  • Skip waiting — принудительная активация через метод self.skipWaiting().
  • После активации нового Service Worker текущие страницы могут быть обновлены через clients.claim().
self.addEventListener('install', event => {
  self.skipWaiting();
});

self.addEventListener('activate', event => {
  event.waitUntil(self.clients.claim());
});

Работа с кэшем через sw-precache

Библиотека sw-precache автоматизирует генерацию Service Worker с заранее закэшированными файлами. Она анализирует проект и создаёт список ресурсов, который затем используется в событии install.

Пример конфигурации sw-precache:

const swPrecache = require('sw-precache');

swPrecache.write('sw.js', {
  staticFileGlobs: [
    'index.html',
    'styles/**/*.css',
    'scripts/**/*.js',
    'images/**/*.{png,jpg,gif,svg}'
  ],
  stripPrefix: '',
  runtimeCaching: [{
    urlPattern: /\/api\//,
    handler: 'networkFirst'
  }]
});

Основные возможности:

  • Автоматическое создание кэшируемого списка ресурсов.
  • Поддержка стратегий кэширования для отдельных URL.
  • Интеграция с инструментами сборки, такими как Gulp и Webpack.

Особенности жизненного цикла с sw-precache

  • Install: sw-precache автоматически кэширует ресурсы из staticFileGlobs.
  • Activate: устаревшие кэши удаляются при изменении версии.
  • Fetch: встроенные обработчики предоставляют гибкие стратегии кэширования для динамических и статических ресурсов.
  • Обновление: при изменении содержимого файлов sw-precache генерирует новый Service Worker с обновлённым кэшем.

Жизненный цикл Service Worker обеспечивает предсказуемое поведение приложения, позволяя контролировать установку, активацию, обработку запросов и обновления кэша. Sw-precache облегчает работу с кэшированием, автоматизируя генерацию Service Worker и минимизируя ошибки ручного управления ресурсами.