Совместная работа NavigationPreload и стратегий

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

Включение Navigation Preload

Для активации Navigation Preload необходимо использовать объект serviceWorkerRegistration.navigationPreload. Чаще всего включение выполняется в событии activate:

self.addEventListener('activate', event => {
  event.waitUntil(
    self.registration.navigationPreload.enable()
  );
});

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

Получение предзагруженного ответа

В событии fetch можно получить предзагруженный запрос через event.preloadResponse:

self.addEventListener('fetch', event => {
  event.respondWith(
    (async () => {
      const preloadResponse = await event.preloadResponse;
      if (preloadResponse) {
        return preloadResponse;
      }
      return fetch(event.request);
    })()
  );
});

Этот подход обеспечивает минимальное время ожидания ответа для навигационных запросов.

Интеграция Navigation Preload со стратегиями Workbox

Workbox предоставляет готовые стратегии кэширования, такие как CacheFirst, NetworkFirst, StaleWhileRevalidate, которые можно комбинировать с Navigation Preload. Наиболее распространённый сценарий — использовать Navigation Preload для NetworkFirst стратегии, чтобы сократить время ответа при сетевых запросах.

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

registerRoute(
  ({ request }) => request.mode === 'navigate',
  new NetworkFirst({
    cacheName: 'pages-cache',
    plugins: [
      {
        fetchDidFail: async ({ request }) => {
          console.log(`Network failed for ${request.url}`);
        }
      }
    ]
  })
);

Чтобы интегрировать Navigation Preload с Workbox, нужно сначала включить preload в сервис-воркере, а затем внутри стратегии использовать его ответ как приоритетный:

self.addEventListener('fetch', event => {
  if (event.request.mode === 'navigate') {
    event.respondWith(
      (async () => {
        const preloadResponse = await event.preloadResponse;
        if (preloadResponse) return preloadResponse;

        const networkFirst = new NetworkFirst({
          cacheName: 'pages-cache'
        });
        return networkFirst.handle({ request: event.request });
      })()
    );
  }
});

Преимущества совместного использования

  • Снижение времени загрузки: Navigation Preload позволяет получать HTML страницы параллельно с активацией сервис-воркера, а стратегия кэширования обеспечивает устойчивость при отсутствии сети.
  • Гибкость стратегий: Любая стратегия Workbox может быть использована поверх Navigation Preload, включая кастомные плагины и логику обработки ошибок.
  • Простая интеграция с кэшированием: NetworkFirst с Navigation Preload позволяет в случае отсутствия сети отдать кэшированную версию страницы, минимизируя зависимость от состояния соединения.

Рекомендации по использованию

  • Navigation Preload особенно полезен для navigate запросов (HTML страниц), но не рекомендуется включать для всех ресурсов, таких как CSS или JS, так как это увеличивает нагрузку на сеть.
  • Стратегия NetworkFirst подходит для динамических страниц, где важно иметь актуальный контент, а CacheFirst лучше использовать для статических ресурсов.
  • Необходимо проверять поддержку Navigation Preload в браузере:
if ('navigationPreload' in self.registration) {
  self.registration.navigationPreload.enable();
}
  • Для сложных приложений можно комбинировать несколько стратегий Workbox для разных типов ресурсов, при этом навигационный запрос всегда отдавать через Navigation Preload.

Практическая схема работы

  1. Пользователь делает навигационный запрос.
  2. Браузер сразу отправляет запрос на сервер (preload).
  3. Сервис-воркер перехватывает fetch и сначала проверяет preloadResponse.
  4. Если preloadResponse доступен, возвращается этот ответ.
  5. В противном случае применяется выбранная стратегия Workbox (NetworkFirst, CacheFirst и др.).
  6. При неудаче сети можно отдать кэшированную версию или fallback страницу.

Такое сочетание обеспечивает баланс между скоростью загрузки, надежностью кэширования и свежестью данных, что критично для современных Progressive Web Apps.