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

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


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

Для использования Service Worker необходимо его зарегистрировать в основном файле приложения:

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

Особенности:

  • Регистрация должна выполняться только после загрузки документа (DOMContentLoaded или в основном JS-файле).
  • Область (scope) определяет, какие запросы будут перехватываться Service Worker.

Структура Service Worker

Основные жизненные циклы Service Worker:

  1. Install — установка и первичное кэширование ресурсов.
  2. Activate — активация нового Service Worker и очистка старых кэшей.
  3. Fetch — перехват сетевых запросов и управление кэшем.

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

const CACHE_NAME = 'lit-app-cache-v1';
const URLS_TO_CACHE = [
  '/',
  '/index.html',
  '/styles.css',
  '/main.js'
];

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

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames =>
      Promise.all(
        cacheNames.map(name => {
          if (name !== CACHE_NAME) {
            return caches.delete(name);
          }
        })
      )
    )
  );
});

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

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

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

  1. Cache First — сначала проверка кэша, затем сеть. Подходит для статических ресурсов, таких как стили и скрипты.
  2. Network First — сначала сеть, затем кэш. Используется для данных, которые должны быть актуальными.
  3. Stale-While-Revalidate — возвращает кэш сразу, но обновляет его в фоне. Баланс между производительностью и актуальностью.

Пример стратегии Stale-While-Revalidate:

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.open(CACHE_NAME).then(cache =>
      cache.match(event.request).then(response => {
        const fetchPromise = fetch(event.request).then(networkResponse => {
          cache.put(event.request, networkResponse.clone());
          return networkResponse;
        });
        return response || fetchPromise;
      })
    )
  );
});

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

Lit строит интерфейс на основе Web Components, что делает работу с Service Worker особенно эффективной:

  • Компоненты могут загружать данные через fetch, который перехватывается Service Worker, обеспечивая офлайн-доступ.
  • Ленивая загрузка компонентов (import() или LitElement с динамическим импортом) легко кэшируется для ускорения повторного открытия страниц.
  • Использование кэша позволяет уменьшить количество сетевых запросов, сохраняя состояние UI компонентов.

Пример кэширования данных API в Lit-компоненте:

import { LitElement, html, css } from 'lit';

class UserList extends LitElement {
  static properties = {
    users: { type: Array }
  };

  constructor() {
    super();
    this.users = [];
  }

  async connectedCallback() {
    super.connectedCallback();
    const response = await fetch('/api/users');
    this.users = await response.json();
  }

  render() {
    return html`
      <ul>
        ${this.users.map(user => html`<li>${user.name}</li>`)}
      </ul>
    `;
  }
}

customElements.define('user-list', UserList);

Здесь fetch перехватывается Service Worker, что позволяет:

  • Предоставлять данные при офлайн-доступе (если они уже кэшированы).
  • Обновлять кэш в фоне без прерывания отображения компонентов.

Оптимизация кэша

  • Использовать версии кэша (cache-v1, cache-v2) для управляемого обновления ресурсов.
  • Ограничивать размер кэша, удаляя старые или редко используемые файлы.
  • Кэшировать только необходимые ресурсы, избегая избыточного хранения больших динамических данных.

Инструменты и рекомендации

  • Workbox — библиотека для упрощенной работы с Service Worker и стратегиями кэширования.
  • Разделение кэша для статических и динамических ресурсов повышает гибкость.
  • Мониторинг обновлений Service Worker помогает корректно уведомлять пользователей о новых версиях приложения.

Service Worker в сочетании с Lit позволяет создать прогрессивное веб-приложение с высокой производительностью, надежностью и поддержкой офлайн-режима, сохраняя динамичность интерфейса и минимизируя задержки при повторных посещениях.