Service Worker в действии: от базовых примеров до продвинутых паттернов в 2025

Service Worker в действии: от базовых примеров до продвинутых паттернов в 2025

Если вы хотите, чтобы ваше веб-приложение работало быстро и стабильно даже при обрыве сети, кэшировало ресурсы и отправляло push-уведомления, то Service Worker — ваш главный инструмент. Давайте разберем реальные примеры, которые я использую в проектах, и избежим распространенных ошибок.

Полное руководство по "service workers примеры"

Service Worker — это не просто скрипт, это прокси-слой между вашим приложением, браузером и сетью. Он работает в отдельном потоке (worker) и может перехватывать сетевые запросы, управлять кэшем и многое другое. В 2025 году это уже не опция, а стандарт для Progressive Web Apps (PWA).

Теоретическая основа и терминология

Давайте сразу проясним ключевые термины, чтобы говорить на одном языке:

  • Service Worker (SW): Скрипт, работающий в фоне.
  • Жизненный цикл: Установка (install), Активация (activate), Ожидание (idle), Завершение (terminated), Захват (fetch).
  • Кэш (Cache API): Хранилище для сетевых ответов, независимое от HTTP-кэша браузера.
  • Манифест (Web App Manifest): JSON-файл, описывающий PWA.

Важно: Service Worker требует HTTPS в продакшене (кроме localhost). Это критически важно для безопасности.

Принцип работы и архитектура

Архитектура строится вокруг событий. Основной файл (например, app.js) регистрирует SW. После регистрации SW переживает этапы установки и активации. После этого он может прослушивать события, главное из которых — fetch.

Вот как выглядит базовая регистрация:

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

Примеры реализации (3 различных сценария)

Пример 1: Статический кэш (Cache First)

Идеально для статичных ресурсов: CSS, JS, шрифты, базовый HTML.

// sw.js
const CACHE_NAME = 'static-cache-v1';
const urlsToCache = [
  '/',
  '/styles/main.css',
  '/scripts/app.js',
  '/images/logo.svg'
];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(urlsToCache))
  );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        // Возвращаем из кэша, если нашли
        if (response) {
          return response;
        }
        // Иначе идем в сеть
        return fetch(event.request);
      })
  );
});

Пример 2: Динамический кэш (Network First, с fallback на кэш)

Для данных API, где важна актуальность, но нужен офлайн-режим.

self.addEventListener('fetch', event => {
  if (event.request.url.includes('/api/')) {
    event.respondWith(
      fetch(event.request)
        .then(response => {
          // Клонируем ответ, т.к. поток можно прочитать один раз
          const responseClone = response.clone();
          caches.open('dynamic-cache-v1')
            .then(cache => cache.put(event.request, responseClone));
          return response;
        })
        .catch(() => caches.match(event.request))
    );
  }
});

Пример 3: Фоновая синхронизация (Background Sync)

Из личного опыта: мы делали приложение для полевых работ с плохим интернетом. Пользователь мог заполнить форму, а отправка происходила автоматически, когда связь появлялась.

// В основном скрипте приложения, после отправки формы:
if ('serviceWorker' in navigator && 'SyncManager' in window) {
  navigator.serviceWorker.ready.then(registration => {
    return registration.sync.register('send-form-data');
  });
}

// В Service Worker:
self.addEventListener('sync', event => {
  if (event.tag === 'send-form-data') {
    event.waitUntil(sendFormData()); // Функция, отправляющая накопленные данные
  }
});

Экспертный совет: Всегда используйте версионирование имен кэшей (например, 'cache-v2'). Это позволяет легко обновлять ресурсы на этапе активации нового SW.

Оптимизация и продвинутые техники

Вот таблица сравнения стратегий кэширования:

СтратегияИспользованиеПлюсыМинусы
Cache FirstСтатика (CSS, JS, иконки)Мгновенная загрузка, работает офлайнРиск устаревшего контента
Network FirstДанные API, часто обновляемый контентАктуальные данныеМедленнее при плохой сети
Stale-While-RevalidateКонтент, где важна и скорость, и актуальностьБыстрый ответ + обновление фонаСложнее в реализации

Предупреждение: Не кэшируйте всё подряд бездумно. Учитывайте лимиты кэша (обычно привязаны к свободному месту на диске) и политики хранения данных.

Подводные камни и ловушки

Однажды на проекте мы столкнулись с "призрачным кэшем". После обновления SW пользователи видели старую версию сайта. Проблема была в том, что мы не удаляли старые кэши на этапе activate. Решение:

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (cacheName !== CACHE_NAME) {
            return caches.delete(cacheName); // Удаляем все старые кэши
          }
        })
      );
    })
  );
});

Еще одна частая ошибка — неправильная обработка Opaque Responses (ответов от других доменов при режиме no-cors). Их кэширование может привести к непредсказуемому поведению.

Будущее технологии

В 2025 году мы видим тренд на более тесную интеграцию с операционными системами. Появляются экспериментальные API, такие как Periodic Background Sync (для периодических фоновых задач) и Web Push с более богатыми возможностями. Service Worker становится ядром не просто "веб-сайта", а полноценного приложения, устанавливаемого на уровне ОС.

Часто задаваемые вопросы (FAQ)

Service Worker — это то же самое, что Web Worker?

Нет. Web Worker предназначен для тяжелых вычислений в фоне. Service Worker — это именно прокси для сетевых запросов, работающий независимо от вкладки.

Как обновить Service Worker?

Браузер обнаруживает новую версию SW-файла (хотя бы 1 байт отличий). Новый worker устанавливается параллельно со старым, но переходит в режим ожидания. Он активируется, когда не останется открытых вкладок, использующих старый worker, или после вызова skipWaiting().

Можно ли использовать Service Worker с фреймворками (React, Vue, Angular)?

Конечно. Часто для этого используются плагины (например, workbox-webpack-plugin), которые автоматически генерируют SW-файл со списком ресурсов для кэширования.

Какие есть актуальные ресурсы для изучения в 2024-2025?

  • Официальная документация MDN: Service Worker API
  • Библиотека Workbox от Google: Workbox (значительно упрощает работу)
  • Курс "Progressive Web Apps" на Udacity.