Service Worker
Service Worker це спеціальний фоновий скрипт, який браузер запускає між сторінкою і мережею: він може перехоплювати мережеві запити, кешувати відповіді та реагувати на події (fetch, push, sync) навіть тоді, коли вкладку закрито. Простіше кажучи, це проксі-сервер усередині браузера, яким ви керуєте з JavaScript.
Теорія
TL;DR
- Service Worker це окремий потік виконання, ізольований від сторінки: без
windowі безdocument. - Він стоїть між сторінкою і мережею і сам вирішує, віддати відповідь з кешу чи піти в мережу.
- Життєвий цикл: реєстрація,
install,activate, робота за подіями, вивантаження. - Основні можливості: перехоплення
fetch, Cache API, push-сповіщення, background sync, periodic sync. - Працює лише через HTTPS (виняток: localhost) і має квоти на розмір кешу.
- Це технологічна основа PWA: офлайн-доступ, миттєве завантаження, сповіщення без відкритої вкладки.
Швидкий приклад
sw.js:
self.addEventListener('install', (event) => {
console.log('Service worker is installing');
event.waitUntil(
caches.open('v1').then((cache) => cache.addAll([
'/',
'/index.html',
'/styles.css',
'/app.js'
]))
);
});
self.addEventListener('activate', () => {
console.log('Service worker is active');
});
self.addEventListener('fetch', (event) => {
console.log('Intercepted request:', event.request.url);
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request); // from cache or from the network
})
);
});Реєстрація в основному коді сторінки:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(() => console.log('Service worker registered'))
.catch(console.error);
}Цей воркер зберігає файли в кеш під час встановлення, перехоплює всі запити і віддає кешовану відповідь, а якщо її немає, іде в мережу.
Архітектура і життєвий цикл
Схематично Service Worker стоїть посередині:
Internet
^
| fetch request
v
+-----------------------+
| Service Worker | proxy between the page and the network
| - intercept fetch |
| - serve from cache |
| - push notifications |
| - background sync |
+-----------------------+
^
|
+-----------------------+
| Page (browser tab)|
+-----------------------+Життєвий цикл складається з п'яти кроків:
- Реєстрація. Сторінка повідомляє браузеру, де лежить файл воркера:
navigator.serviceWorker.register('/sw.js'). - Встановлення (
install). Браузер завантажує скрипт і встановлює його один раз. Тут зазвичай наповнюють кеш черезevent.waitUntil(...). - Активація (
activate). Старі версії воркера знімаються з реєстрації, новий стає активним. Тут прибирають застарілі кеші. - Робота (
fetch/push/sync). Після активації воркер слухає події:fetchперехоплює запити,pushприймає сповіщення,syncвиконує фонові задачі. - Вивантаження (idle / terminate). Коли воркер не потрібен, браузер вивантажує його з пам'яті і «будить» знову на наступній події.
Що вміє Service Worker
| Можливість | Що робить |
|---|---|
| Fetch interception | Перехоплює і контролює всі мережеві запити сторінки |
| Caching API | Зберігає файли та відповіді в кеші, це дає роботу офлайн |
| Background sync | Виконує відкладені задачі, коли мережа відновиться |
| Push notifications | Отримує push-повідомлення від сервера і показує їх |
| Offline-first | Дозволяє застосунку працювати без інтернету |
| Periodic sync | Виконує дії за розкладом |
| Proxy layer | Додає контроль над запитами і відповідями |
Офлайн-кеш і fallback-сторінка
Найпростіший офлайн-сценарій: спробувати мережу, а при помилці віддати заздалегідь закешовану сторінку.
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request).catch(() => caches.match('/offline.html'))
);
});Якщо інтернету немає, користувач бачить /offline.html замість помилки браузера: застосунок не «падає», а показує повідомлення «Ви офлайн».
Під час активації варто чистити застарілі версії кешу, інакше квота швидко закінчиться:
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((keys) => Promise.all(
keys.filter((key) => key !== 'v1').map((key) => caches.delete(key))
))
);
});Push-сповіщення і background sync
Push працює навіть із закритою вкладкою: браузер «будить» Service Worker, щоб той обробив подію.
self.addEventListener('push', (event) => {
const data = event.data.json();
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body,
icon: '/icon.png'
})
);
});Background sync дає змогу відкласти задачу до появи мережі:
self.addEventListener('sync', (event) => {
if (event.tag === 'sendFormData') {
event.waitUntil(sendDataToServer());
}
});Типовий сценарій: користувач офлайн, дані форми лягають в IndexedDB, а коли мережа відновиться, Service Worker сам відправить їх на сервер.
Обмеження і де застосовують
| Особливість | Опис |
|---|---|
| Ізольований від DOM | Немає window і document, зі сторінкою спілкується через postMessage |
| Тільки HTTPS | Працює лише на захищених доменах, виняток становить localhost |
| Обмежений обсяг сховища | Браузер дає квоту на кеш і може очистити його |
| Автоматично вивантажується | «Прокидається» за подіями, не живе постійно |
Де це реально використовують:
- PWA (Progressive Web Apps): офлайн-доступ, «додати на екран», миттєве завантаження.
- Новини і чати: push-сповіщення без відкритої вкладки.
- Ігри та офлайн-режими: попереднє завантаження ассетів і даних у кеш.
- Веб-сервіси: кешування відповідей API і економія трафіку.
Підсумок одним поглядом:
| Параметр | Опис |
|---|---|
| Тип | Фоновий JS-потік між сторінкою і мережею |
| Головні функції | Перехоплення запитів, кеш, push, background sync |
| Працює при закритій вкладці | Так |
| Доступ до DOM | Ні |
| Потребує HTTPS | Так |
| Основне застосування | PWA, офлайн-режим, сповіщення |
Типові помилки
- Думати, що Service Worker це те саме, що Web Worker. Web Worker рахує щось у фоні для однієї сторінки, Service Worker керує мережею для всіх вкладок свого scope і живе довше за них.
- Звертатися до
documentабоwindowусередині воркера. Їх там немає, обмін даними йде черезpostMessageіclients. - Забути про очищення старих кешів в
activate. Версії накопичуються, і браузер зрештою знесе весь кеш за квотою. - Кешувати все підряд, зокрема відповіді API з авторизацією. Користувач може побачити чужі або застарілі дані.
- Очікувати, що новий воркер підхопиться одразу. Після оновлення він чекає стану waiting, поки не закриють старі вкладки, якщо не викликати
skipWaiting()іclients.claim(). - Не передбачити відкат. Помилковий
fetch-обробник може «зламати» сайт для вже встановлених користувачів, тому потрібен шлях до розреєстрації воркера.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.