Service workers

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


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

Service Worker регистрируется в основном скрипте страницы через объект navigator.serviceWorker. Ключевой момент — регистрация должна происходить только на страницах, доступных через HTTPS, за исключением localhost, где разрешено тестирование.

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

Особенности регистрации:

  • Скрипт Service Worker исполняется отдельно от страницы.
  • Каждое обновление скрипта требует новой версии, браузер проверяет изменения автоматически.
  • Событие updatefound позволяет отслеживать появление новой версии.

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

Жизненный цикл Service Worker состоит из нескольких стадий:

  1. Install (установка) На этом этапе создаются кэши и подготавливаются ресурсы для работы оффлайн. Обработчик события install обычно используется для предварительного кэширования статических файлов.

    self.addEventListener('install', event => {
        event.waitUntil(
            caches.open('v1').then(cache => {
                return cache.addAll([
                    '/index.html',
                    '/styles.css',
                    '/script.js'
                ]);
            })
        );
    });
  2. Activate (активация) Событие activate используется для очистки старых кэшей и подготовки нового Service Worker к управлению страницей.

    self.addEventListener('activate', event => {
        event.waitUntil(
            caches.keys().then(keys => {
                return Promise.all(
                    keys.filter(key => key !== 'v1')
                        .map(key => caches.delete(key))
                );
            })
        );
    });
  3. Fetch (перехват запросов) Service Worker может перехватывать сетевые запросы и возвращать закэшированные данные или выполнять сетевой запрос.

    self.addEventListener('fetch', event => {
        event.respondWith(
            caches.match(event.request)
                .then(response => response || fetch(event.request))
        );
    });
  4. Update (обновление) Обновление Service Worker происходит автоматически при обнаружении изменений в скрипте. Новая версия переходит в стадию установки, пока старая еще активна. Переключение происходит после закрытия всех вкладок, использующих старую версию.


Кэширование ресурсов

Кэширование позволяет ускорить загрузку приложения и обеспечить оффлайн-доступ. Основные стратегии кэширования:

  • Cache First — сначала проверяется кэш, если ресурс найден — возвращается, иначе выполняется сетевой запрос.
  • Network First — сначала выполняется сетевой запрос, если сеть недоступна — используется кэш.
  • Stale-While-Revalidate — отдаётся закэшированный ресурс сразу, затем обновляется кэш в фоне.

Пример стратегии Cache First:

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

Push-уведомления и фоновые задачи

Service Worker поддерживает push-уведомления и фоновую синхронизацию данных. Это позволяет уведомлять пользователя о событиях или обновлениях без активной вкладки.

Пример обработки push-события:

self.addEventListener('push', event => {
    const data = event.data.json();
    self.registration.showNotification(data.title, {
        body: data.body,
        icon: '/icon.png'
    });
});

Фоновая синхронизация:

self.addEventListener('sync', event => {
    if (event.tag === 'sync-data') {
        event.waitUntil(syncDataToServer());
    }
});

Ограничения и безопасность

Service Worker имеет ряд ограничений:

  • Работа только по HTTPS (кроме localhost).
  • Отсутствие доступа к DOM напрямую. Все взаимодействия с интерфейсом выполняются через postMessage.
  • Ограниченный срок жизни в памяти: после завершения всех событий Service Worker может быть выгружен.

Безопасность: необходимо избегать хранения конфиденциальных данных в открытых кэших, так как кэш может быть доступен через злоумышленника при XSS-атаках.


Взаимодействие с клиентом

Для связи Service Worker и страницы используется метод postMessage. Это позволяет передавать данные и получать статус операций, таких как загрузка ресурсов или обработка синхронизации.

// В Service Worker
self.addEventListener('message', event => {
    console.log('Сообщение от клиента:', event.data);
    event.source.postMessage('Данные получены');
});

// На странице
navigator.serviceWorker.controller.postMessage('Привет, SW!');
navigator.serviceWorker.addEventListener('message', event => {
    console.log('Ответ от SW:', event.data);
});

Service Worker — фундаментальный инструмент для построения прогрессивных веб-приложений (PWA), обеспечивающий оффлайн-доступ, кэширование, уведомления и фоновые процессы. Правильное использование жизненного цикла и стратегий кэширования позволяет создавать быстрые, надежные и удобные веб-приложения.