Service Workers и кэширование

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

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

Для подключения Service Worker используется метод navigator.serviceWorker.register. Обычно регистрация выполняется в основном скрипте приложения после загрузки DOM:

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

Ключевые моменты:

  • Проверка наличия serviceWorker в navigator обязательна, чтобы избежать ошибок в браузерах, которые не поддерживают эту технологию.
  • Путь '/sw.js' должен быть относительно корня сайта и соответствовать правилам области действия (scope).

Структура Service Worker

Файл sw.js содержит логику кэширования, обработки запросов и событий жизненного цикла. Основные события:

  • install — установка Service Worker, обычно используется для предварительного кэширования ресурсов.
  • activate — активация нового Service Worker и очистка устаревших кэшей.
  • fetch — перехват сетевых запросов для отдачи закэшированных ресурсов или получения их с сервера.

Пример базового Service Worker:

const CACHE_NAME = 'mithril-app-v1';
const ASSETS_TO_CACHE = [
    '/',
    '/index.html',
    '/app.js',
    '/style.css'
];

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

self.addEventListener('activate', event => {
    event.waitUntil(
        caches.keys().then(keys =>
            Promise.all(
                keys.filter(key => key !== CACHE_NAME)
                    .map(key => caches.delete(key))
            )
        )
    );
    self.clients.claim();
});

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

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

Важные аспекты кэширования:

  1. Стратегии кэширования:

    • Cache First: отдаёт ресурс из кэша, если он есть; иначе делает запрос к сети.
    • Network First: сначала пробует сеть, если недоступна — отдаёт кэш.
    • Stale While Revalidate: отдаёт кэш мгновенно, а параллельно обновляет его из сети.
  2. Версионирование кэша:

    • Каждый новый релиз приложения должен создавать новый кэш с уникальным именем.
    • Устаревшие кэши удаляются при событии activate.
  3. Динамическое кэширование:

    • Для данных API запросов можно кэшировать ответы на лету, используя caches.put.

Пример динамического кэширования данных:

self.addEventListener('fetch', event => {
    if (event.request.url.includes('/api/')) {
        event.respondWith(
            fetch(event.request)
                .then(response => {
                    return caches.open(CACHE_NAME).then(cache => {
                        cache.put(event.request, response.clone());
                        return response;
                    });
                })
                .catch(() => caches.match(event.request))
        );
    }
});

Интеграция с Mithril

В Mithril Service Worker работает независимо от виртуального DOM. Для максимальной пользы рекомендуется:

  • Предварительно кэшировать статические ресурсы приложения (app.js, стили, шаблоны).
  • Использовать динамическое кэширование для данных API, чтобы страницы могли работать оффлайн.
  • Обновлять кэш после релиза, чтобы пользователи получали свежую версию без ошибок.

Работа с оффлайн-режимом

С Service Worker можно полностью эмулировать оффлайн-режим. Для Mithril это означает:

  • Компоненты могут отображать закэшированные данные при отсутствии сети.
  • Отправка форм и обновление данных может временно сохраняться в IndexedDB и синхронизироваться при восстановлении сети.
  • Можно реализовать уведомления пользователя о недоступности сети через глобальное состояние приложения.

Лайфхаки для производительности

  • Минимизировать количество кэшируемых ресурсов, оставляя только критичные.
  • Использовать компрессию и минимизацию JS/CSS перед кэшированием.
  • Применять стратегию Stale While Revalidate для часто меняющихся ресурсов, чтобы пользователи видели актуальный контент без задержек.

Service Workers позволяют создать быстрые, надежные и оффлайн-готовые приложения на Mithril, обеспечивая кэширование, контроль версий и улучшенное взаимодействие с сетью.