Сборка ответа из нескольких источников

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

Использование CacheFirst и NetworkFirst в комбинации

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

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

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

registerRoute(
  ({ url }) => url.pathname.startsWith('/api/data'),
  async ({ request }) => {
    const cacheStrategy = new CacheFirst({
      cacheName: 'api-cache',
    });

    const networkStrategy = new NetworkFirst({
      cacheName: 'api-network-cache',
    });

    const [cacheResponse, networkResponse] = await Promise.all([
      cacheStrategy.handle({ request }),
      networkStrategy.handle({ request })
    ]);

    let mergedData = {};

    if (cacheResponse) {
      const cacheJson = await cacheResponse.json();
      Object.assign(mergedData, cacheJson);
    }

    if (networkResponse) {
      const networkJson = await networkResponse.json();
      Object.assign(mergedData, networkJson);
    }

    return new Response(JSON.stringify(mergedData), {
      headers: { 'Content-Type': 'application/json' }
    });
  }
);

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

  • Promise.all позволяет параллельно получить ответ из кэша и сети.
  • Object.assign или другой метод объединения данных позволяет гибко комбинировать разные источники.
  • Возвращаемый объект Response должен иметь корректный тип контента (application/json для JSON).

Динамическая сборка ответа из нескольких ресурсов

Workbox поддерживает возможность комбинировать не только один источник кэша и один сетевой ресурс, но и несколько разных эндпоинтов. Это делается через асинхронные функции внутри обработчика маршрута.

Пример запроса к нескольким API и объединения результатов:

registerRoute(
  ({ url }) => url.pathname === '/api/combined',
  async () => {
    const urls = ['/api/user', '/api/settings', '/api/notifications'];

    const responses = await Promise.all(urls.map(url => fetch(url).then(res => res.json())));

    const combined = responses.reduce((acc, data) => Object.assign(acc, data), {});

    return new Response(JSON.stringify(combined), {
      headers: { 'Content-Type': 'application/json' }
    });
  }
);

Особенности подхода:

  • fetch позволяет напрямую обращаться к сети без использования стратегии кэширования, если необходимы актуальные данные.
  • reduce аккуратно объединяет объекты в один, сохраняя структуру данных.
  • Этот метод применим для API, возвращающих JSON, но может быть адаптирован под другие форматы, например, HTML или текст.

Управление приоритетами и таймаутами

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

import { NetworkFirst } from 'workbox-strategies';
import { TimeoutPlugin } from 'workbox-expiration';

const networkStrategy = new NetworkFirst({
  cacheName: 'api-network-cache',
  plugins: [
    new TimeoutPlugin({
      maxAgeSeconds: 5,
    }),
  ],
});

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

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

Кэширование отдельных частей ответа

В сложных приложениях иногда требуется кэшировать не весь объединённый ответ, а только его части. Для этого Workbox позволяет работать с Cache API напрямую внутри обработчика маршрута:

registerRoute(
  ({ url }) => url.pathname.startsWith('/api/data'),
  async ({ request }) => {
    const cache = await caches.open('partial-cache');
    
    const userResponse = await fetch('/api/user');
    cache.put('/api/user', userResponse.clone());

    const settingsResponse = await fetch('/api/settings');
    cache.put('/api/settings', settingsResponse.clone());

    const combined = {
      user: await userResponse.json(),
      settings: await settingsResponse.json()
    };

    return new Response(JSON.stringify(combined), {
      headers: { 'Content-Type': 'application/json' }
    });
  }
);

Преимущества такого подхода:

  • Позволяет переиспользовать отдельные ресурсы без повторного сетевого запроса.
  • Обеспечивает более гибкую стратегию обновления данных.
  • Удобно для приложений с частично статическим контентом.

Заключение по сборке ответа

Использование Workbox для комбинирования нескольких источников данных позволяет создавать сложные, отзывчивые и кэшируемые приложения. Стратегии могут варьироваться от простого объединения кэша и сети до сложного динамического слияния нескольких API с управлением таймаутами, приоритетами и частичным кэшированием. Гибкость Workbox делает такие подходы масштабируемыми и легко поддерживаемыми в больших приложениях.