Ограничение количества записей в кэше

Библиотека Workbox предоставляет мощные средства для управления кэшированием ресурсов в приложениях на JavaScript. Одним из важных аспектов оптимизации работы сервис-воркеров является контроль объема кэша и числа хранимых записей. Избыточное накопление кэша может привести к замедлению работы приложения, переполнению памяти устройства и нежелательным побочным эффектам при обновлениях ресурсов. Workbox предлагает встроенные механизмы для ограничения количества записей в кэше, что делает управление кэшированием предсказуемым и безопасным.

Конфигурация стратегии кэширования с ограничением количества записей

В Workbox для ограничения числа элементов в кэше используется объект ExpirationPlugin из пакета workbox-expiration. Основная функция этого плагина — контролировать время хранения записей и максимальное количество элементов в кэше.

Пример базовой конфигурации:

import { registerRoute } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';

registerRoute(
  ({ request }) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'images-cache',
    plugins: [
      new ExpirationPlugin({
        maxEntries: 50,          // Максимальное количество записей в кэше
        maxAgeSeconds: 30 * 24 * 60 * 60, // Время жизни записи в секундах (30 дней)
        purgeOnQuotaError: true, // Автоматическая очистка при нехватке места
      }),
    ],
  })
);

В этом примере:

  • maxEntries ограничивает число кэшированных изображений до 50. Если добавляется новый элемент, а лимит достигнут, Workbox удаляет наименее недавно использованные записи (LRU — Least Recently Used).
  • maxAgeSeconds устанавливает срок хранения кэша. После его истечения запись считается устаревшей и подлежит удалению.
  • purgeOnQuotaError активирует автоматическую очистку кэша при нехватке дискового пространства, предотвращая ошибки записи.

Ограничение количества записей в различных стратегиях

1. CacheFirst

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

new CacheFirst({
  cacheName: 'static-resources',
  plugins: [
    new ExpirationPlugin({ maxEntries: 100 })
  ],
});

2. NetworkFirst

Стратегия NetworkFirst запрашивает ресурс с сети и только при её недоступности возвращает кэшированную версию. Даже здесь ограничение количества записей важно для предотвращения переполнения кэша:

import { NetworkFirst } from 'workbox-strategies';

registerRoute(
  ({ request }) => request.destination === 'document',
  new NetworkFirst({
    cacheName: 'html-cache',
    plugins: [
      new ExpirationPlugin({ maxEntries: 20 })
    ],
  })
);

3. StaleWhileRevalidate

Стратегия StaleWhileRevalidate отдаёт старую копию кэша мгновенно, параллельно обновляя её с сети. Плагин ExpirationPlugin обеспечивает контроль над количеством и сроком хранения устаревших данных:

import { StaleWhileRevalidate } from 'workbox-strategies';

registerRoute(
  ({ request }) => request.destination === 'script',
  new StaleWhileRevalidate({
    cacheName: 'scripts-cache',
    plugins: [
      new ExpirationPlugin({ maxEntries: 30 })
    ],
  })
);

Особенности поведения ExpirationPlugin

  • LRU-удаление: Workbox всегда удаляет наименее недавно использованные записи, когда достигается maxEntries.
  • Комбинирование с maxAgeSeconds: можно одновременно ограничивать количество и возраст записей. Старые элементы будут удаляться даже при недостатке объема.
  • Поддержка разных кэшей: для каждого типа ресурса (изображения, скрипты, CSS) можно создавать отдельный кэш с индивидуальными лимитами.

Динамическая очистка кэша

Иногда требуется не просто ограничить количество, а управлять кэшем программно. Workbox позволяет это делать через API кэширования:

const cacheName = 'dynamic-cache';
const maxEntries = 50;

async function cleanUpCache() {
  const cache = await caches.open(cacheName);
  const keys = await cache.keys();
  if (keys.length > maxEntries) {
    const excess = keys.length - maxEntries;
    for (let i = 0; i < excess; i++) {
      await cache.delete(keys[i]);
    }
  }
}

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

Практические рекомендации

  • Для статических ресурсов, редко обновляемых, лучше использовать CacheFirst с maxEntries и maxAgeSeconds.
  • Для динамических данных, таких как API-запросы, оптимально сочетать NetworkFirst и лимит на количество записей.
  • Всегда включать purgeOnQuotaError, особенно для мобильных устройств, чтобы избежать проблем при переполнении памяти.

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