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;
}
Можно также добавлять метрики времени ответа или статистику кэширования для анализа производительности.