Service Worker
Прокси-скрипт между страницей и сетью: offline-кэш, push, фоновая синхронизация, ядро PWA.
Что это
Отдельный JS-поток, зарегистрированный для origin'а. Перехватывает fetch-запросы со страниц этого origin'а, может ответить из Cache API или сети. Не имеет доступа к DOM. Живёт независимо от вкладок — может работать ещё 30 секунд — 5 минут после закрытия всех вкладок. Lifecycle: install → waiting → activate → idle/fetch/message.
Базовое использование
// main.js — регистрация
if ('serviceWorker' in navigator) {
const reg = await navigator.serviceWorker.register('/sw.js', {
type: 'module', // если используешь import внутри
scope: '/',
});
console.log('SW registered', reg.scope);
}
// sw.js — установка: прогрев кэша
const CACHE = 'v1';
const ASSETS = ['/', '/app.js', '/styles.css', '/offline.html'];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE).then((cache) => cache.addAll(ASSETS))
);
self.skipWaiting; // активироваться немедленно
});
self.addEventListener('activate', (event) => {
// Удалить старые кэши
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)))
)
);
self.clients.claim; // взять контроль над уже открытыми вкладками
});
self.addEventListener('fetch', (event) => {
// Cache-first стратегия
event.respondWith(
caches.match(event.request).then((cached) => cached || fetch(event.request))
);
});
// Сообщения от вкладок
self.addEventListener('message', (event) => {
if (event.data?.type === 'skipWaiting') self.skipWaiting;
});
Жизненный цикл
| Фаза | Когда / что |
|---|---|
| install | Один раз при новом SW. Прогрев кэша. event.waitUntil блокирует переход |
| waiting | SW зарегистрирован, но старый ещё контролирует вкладки. skipWaiting ускоряет |
| activate | Чистка старых кэшей. clients.claim берёт управление существующими вкладками |
| idle / fetch / message / push / sync | Рабочий цикл |
Главные API
| API | Что |
|---|---|
caches.open(name) → Cache |
Хранилище Request→Response |
cache.addAll([urls]) |
Прогрев из массива URL |
cache.match(req) / caches.match(req) |
Поиск ответа в кэше |
clients.matchAll / clients.claim |
Доступ к вкладкам |
self.registration.showNotification |
Push-нотификации |
event.waitUntil(promise) |
Продлевает жизнь SW до резолва |
Требования
- HTTPS или
localhost(иначе не зарегистрируется) sw.jsдолжен быть в том же origin- Scope ограничен папкой
sw.js(/sw.jsконтролирует всё;/foo/sw.js— только/foo/*)
Подводные камни
- install единоразовый — фикс на новой версии SW (меняй имя кэша или contents)
- Между деплоями старый SW отдаёт старый код — нужна стратегия инвалидации (
skipWaiting,clients.claim, версионирование) console.logвнутри SW не виден в обычной DevTools-консоли — откройchrome://serviceworker-internalsили Application → Service Workers- В фазе install JS прекомпилируется на 100% — отсюда популярный трюк прогрева JS через SW
fetchevents работают только для запросов в scope; навигация на cross-origin не перехватывается- BroadcastChannel не работает внутри SW — используй postMessage к клиентам
Используется в bootcamp
- PWA-задачи (если будут) — offline-кэш статики
- Подкаст-плеер мог бы кэшировать эпизоды для offline-прослушивания
Ссылки
🎓 Источники
- ⚡ Service Worker для PWA приложений · AsForJS · 2026-01-26
- SW — сердце PWA. Один SW на все вкладки. install прекомпилирует JS на 100% (vs ~40% в обычном V8 кэше).
- Один WebSocket внутри SW обслуживает все вкладки → экономия серверных коннекшенов.
- SW работает 30 сек — 5 мин после закрытия всех вкладок.
- BroadcastChannel НЕ работает внутри SW — нужен лидер-вкладка.
- 🎓 🔀 Что могут Service Worker — Local-First подход · TimurShemsedinov · 2025-12-09
- 🎓 Progressive Web Applications PWA и ServiceWorkers · TimurShemsedinov · 2019-10-03
- Жизненный цикл: installing → waiting → active,
caches.open()+cache.addAllв install,caches.matchв fetch event.
- Жизненный цикл: installing → waiting → active,
- 🎓 ⎡dlgs01⎦ JavaScript Беседы Service Worker-ы · AsForJS · 2023-11-19