Представьте, что ваш сайт может работать без интернета, мгновенно загружаться при повторном посещении и отправлять push-уведомления, даже когда вкладка закрыта. Это не магия будущего, а реальность, которую дарят Service Workers — революционная технология, лежащая в основе современных Progressive Web Apps (PWA). В этой статье мы разберемся, что это такое, и рассмотрим конкретные, рабочие примеры, которые вы сможете применить уже сегодня.
Что такое Service Worker?
Service Worker — это скрипт, который ваш браузер запускает в фоновом режиме, отдельно от веб-страницы. Он действует как прокси-сервер между вашим приложением, браузером и сетью. Его ключевая особенность — он может перехватывать сетевые запросы, кэшировать ресурсы и доставлять их из кэша, что позволяет создавать офлайн-опыт.
Service Worker работает в отдельном потоке (worker) и не имеет доступа к DOM. Общение с основной страницей происходит через API сообщений (postMessage).
Жизненный цикл Service Worker
Понимание жизненного цикла критически важно для работы:
- Регистрация: Скрипт регистрируется с главной страницы.
- Установка: Происходит один раз для новой версии. Идеальное время для предварительного кэширования ключевых ресурсов.
- Активация: Новый worker активируется, старый очищается. Здесь можно удалить старые кэши.
- Простой (Idle): Worker ждет событий (fetch, push, sync).
- Завершение (Terminated): Браузер может остановить worker для экономии ресурсов.
Практические примеры Service Worker
Пример 1: Базовый офлайн-кэш
Самый распространенный сценарий — кэширование статических ресурсов для работы без сети.
// sw.js
const CACHE_NAME = 'my-site-cache-v1';
const urlsToCache = [
'/',
'/styles/main.css',
'/script/app.js',
'/images/logo.png'
];
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: Стратегия "Сеть, затем кэш" (Fallback)
Идеально для динамического контента, где важна актуальность.
self.addEventListener('fetch', event => {
event.respondWith(
fetch(event.request) // Пытаемся получить из сети
.then(response => {
// Клонируем ответ, т.к. поток можно прочитать один раз
const responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(cache => cache.put(event.request, responseToCache));
return response;
})
.catch(() => caches.match(event.request)) // Если сеть недоступна — из кэша
);
});
Всегда используйте event.respondWith() для асинхронного ответа на fetch-события. И помните про клонирование Response!
Пример 3: Фоновые push-уведомления
Service Worker — единственное место, где можно обрабатывать push-сообщения.
self.addEventListener('push', event => {
const title = 'Новое уведомление!';
const options = {
body: event.data.text(),
icon: '/icon-192.png',
badge: '/badge-72.png'
};
event.waitUntil(
self.registration.showNotification(title, options)
);
});
self.addEventListener('notificationclick', event => {
event.notification.close();
event.waitUntil(
clients.openWindow('https://ваш-сайт.ru/спец-страница') // Открываем страницу
);
});
Регистрация Service Worker на странице
Самый worker бесполезен без его подключения в основном JavaScript вашего приложения.
// main.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('SW зарегистрирован:', registration);
})
.catch(error => {
console.log('Ошибка регистрации SW:', error);
});
});
}
Лучшие практики и подводные камни
- HTTPS обязателен: В production Service Worker работает только на защищенных соединениях (localhost — исключение).
- Контроль версий: Изменение скрипта даже на байт приводит к установке новой версии. Используйте разные имена кэшей (my-cache-v1, v2...).
- Очистка старых кэшей в событии 'activate':
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.filter(name => name !== CACHE_NAME)
.map(name => caches.delete(name))
);
})
);
});
- Не кэшируйте всё подряд: Стратегически выбирайте ресурсы для кэша, чтобы не превышать лимиты браузера.
FAQ: Часто задаваемые вопросы
Service Worker — это то же самое, что Web Worker?
Нет. Web Worker предназначен для вычислительно тяжелых задач в фоне. Service Worker — это именно прокси для сети с событиями жизненного цикла, созданный для управления кэшем и офлайн-работой.
Можно ли использовать Service Worker с любым фреймворком (React, Vue, Angular)?
Да, абсолютно. Service Worker — это нативный браузерный API. Вы можете интегрировать его в любой проект. Многие фреймворки имеют готовые плагины или инструменты (например, workbox-webpack-plugin).
Как обновить уже установленный Service Worker?
При изменении файла sw.js браузер обнаружит это и начнет установку новой версии. Однако она активируется только когда не останется открытых вкладок, использующих старую версию. Вы можете ускорить это, вызвав self.skipWaiting() в событии install и clients.claim() в activate.
Service Worker замедляет сайт?
При правильной реализации — нет, а ускоряет! За счет отдачи ресурсов из локального кэша первый и повторный доступ становятся мгновенными. Главное — не перегружать логику обработки fetch-событий.
Где можно посмотреть зарегистрированных Service Worker?
В Chrome DevTools: вкладка Application -> раздел Service Workers. Там же можно их принудительно обновить, остановить или перевести в офлайн-режим для тестирования.