Создание собственной стратегии

Workbox — это мощная библиотека для управления кэшированием и офлайн-поведения веб-приложений. Хотя в Workbox уже встроены готовые стратегии, такие как CacheFirst, NetworkFirst, StaleWhileRevalidate, иногда возникает необходимость создания кастомной стратегии для тонкой настройки поведения сервис-воркера.


Определение пользовательской стратегии

Пользовательская стратегия в Workbox создается путем наследования класса Workbox.strategies.Strategy или реализации интерфейса, который ожидает метод handle с конкретной сигнатурой. Этот метод вызывается для обработки запроса, где можно внедрить собственную логику кэширования, обработки ошибок и взаимодействия с сетью.

Пример базовой структуры кастомной стратегии:

import { Strategy } from 'workbox-strategies';

class CustomStrategy extends Strategy {
  constructor(options = {}) {
    super(options);
    this.options = options;
  }

  async _handle(request, handler) {
    // Здесь реализуется логика обработки запроса
  }
}

Метод _handle принимает два параметра: request (объект Request) и handler — экземпляр Handler, который предоставляет стандартные методы доступа к кэшу и сети.


Взаимодействие с сетью и кэшем

Для работы с сетью используется метод handler.fetch(request), который инициирует запрос к серверу, а для работы с кэшем — handler.cacheMatch(request) и handler.cachePut(request, response). Эти методы обеспечивают корректную интеграцию с внутренними механизмами Workbox и позволяют переиспользовать уже существующие функции стратегий.

Пример логики с сетевой проверкой и кэшированием:

async _handle(request, handler) {
  try {
    const response = await handler.fetch(request);
    // Проверка успешного ответа перед записью в кэш
    if (response && response.ok) {
      await handler.cachePut(request, response.clone());
    }
    return response;
  } catch (error) {
    const cachedResponse = await handler.cacheMatch(request);
    if (cachedResponse) {
      return cachedResponse;
    }
    throw error;
  }
}

Добавление условий для кэширования

Кастомная стратегия позволяет создавать условные правила кэширования. Например, можно кэшировать только определенные типы ресурсов или ограничивать размер кэша:

async _handle(request, handler) {
  const response = await handler.fetch(request);
  if (response && response.ok && request.destination === 'script') {
    await handler.cachePut(request, response.clone());
  }
  return response;
}

В этом примере кэшируются только JavaScript-файлы, что полезно для оптимизации расхода дискового пространства и уменьшения времени отклика.


Реализация повторных попыток при ошибках

Кастомная стратегия может содержать логику retry. Часто это необходимо для нестабильных сетей:

async _handle(request, handler) {
  const maxRetries = 3;
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await handler.fetch(request);
      if (response && response.ok) {
        await handler.cachePut(request, response.clone());
        return response;
      }
    } catch (err) {
      if (attempt === maxRetries - 1) throw err;
    }
  }
}

Таким образом, стратегия выполняет несколько попыток сетевого запроса перед возвратом ошибки, улучшая устойчивость приложения к временным сбоям.


Комбинирование стратегий

Пользовательские стратегии позволяют комбинировать существующие стратегии Workbox. Например, можно объединить CacheFirst для статических ресурсов и NetworkFirst для динамических данных внутри одного обработчика:

import { CacheFirst, NetworkFirst } from 'workbox-strategies';

class HybridStrategy extends Strategy {
  constructor(options = {}) {
    super(options);
    this.cacheFirst = new CacheFirst();
    this.networkFirst = new NetworkFirst();
  }

  async _handle(request, handler) {
    if (request.destination === 'image') {
      return this.cacheFirst.handle({ request, handler });
    }
    return this.networkFirst.handle({ request, handler });
  }
}

Такой подход упрощает поддержку сложной логики кэширования и позволяет оптимизировать поведение приложения для различных типов ресурсов.


Настройка логирования и анализа

Workbox предоставляет возможность интегрировать логирование в пользовательскую стратегию. Это особенно полезно при отладке сложной логики:

async _handle(request, handler) {
  console.log('Обработка запроса:', request.url);
  const response = await handler.fetch(request);
  console.log('Получен ответ:', response.status);
  return response;
}

Можно также добавлять метрики времени ответа или статистику кэширования для анализа производительности.