Мгновенная навигация

Дополнение традиционных методов предварительной выборки с помощью сервис-воркеров.

Демиан Рензулли
Demián Renzulli
Джильберто Кокки
Gilberto Cocchi

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

С технической точки зрения, перемещение по разным страницам означает выполнение навигационного запроса . Как правило, вы не хотите использовать долгоживущие заголовки Cache-Control для кэширования HTML-ответа для навигационного запроса. Обычно они должны удовлетворяться через сеть с помощью Cache-Control: no-cache , чтобы гарантировать, что HTML вместе с цепочкой последующих сетевых запросов является (разумно) новым. К сожалению, необходимость идти против сети каждый раз, когда пользователь переходит на новую страницу, означает, что каждая навигация может быть медленной — по крайней мере, это означает, что она не будет надежно быстрой.

Чтобы ускорить эти запросы, если вы можете предвидеть действия пользователя, вы можете запросить эти страницы и активы заранее и хранить их в кэше в течение короткого периода времени, пока пользователь не нажмет на эти ссылки. Этот метод называется предварительной выборкой и обычно реализуется путем добавления тегов <link rel="prefetch"> к страницам, указывающих ресурс для предварительной выборки.

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

Производственные случаи

MercadoLibre — крупнейший сайт электронной коммерции в Латинской Америке. Для ускорения навигации они динамически вставляют теги <link rel="prefetch"> в некоторые части потока. Например, на страницах со списком они извлекают следующую страницу результатов, как только пользователь прокручивает список до конца:

Скриншот первой и второй страниц листинга MercadoLibre и тег предварительной загрузки ссылок, соединяющий их.

Предварительно загруженные файлы запрашиваются с приоритетом "самый низкий" и сохраняются в кэше HTTP или кэше памяти (в зависимости от того, кэшируется ресурс или нет) в течение времени, которое различается в зависимости от браузера. Например, начиная с Chrome 85, это значение составляет 5 минут. Ресурсы хранятся в течение пяти минут, после чего применяются обычные правила Cache-Control для ресурса.

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

Например, итальянский спортивный портал Virgilio Sport использует service workers для предварительной выборки самых популярных постов на своей домашней странице. Они также используют API сетевой информации , чтобы избежать предварительной выборки для пользователей, которые находятся на 2G-подключении.

Логотип Virgilio Sport.

В результате за 3 недели наблюдений Virgilio Sport отметила, что время загрузки статей улучшилось на 78% , а количество показов статей увеличилось на 45% .

Скриншот домашней страницы и страниц статей Virgilio Sport с показателями воздействия после предварительной загрузки.

Реализуйте предварительное кэширование с помощью Workbox

В следующем разделе мы воспользуемся Workbox , чтобы показать, как реализовать различные методы кэширования в Service Worker, которые можно использовать в качестве дополнения к <link rel="prefetch"> или даже в качестве его замены, полностью делегировав эту задачу Service Worker.

1. Предварительное кэширование статических страниц и подресурсов страниц

Предварительное кэширование — это способность Service Worker сохранять файлы в кэше во время установки.

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

Предварительное кэширование статических страниц

Для страниц, которые генерируются во время сборки (например, about.html , contact.html ) или на полностью статических сайтах, можно просто добавить документы сайта в список предварительного кэширования, чтобы они были доступны в кэше каждый раз, когда пользователь обращается к ним:

workbox.precaching.precacheAndRoute([
  {url: '/about.html', revision: 'abcd1234'},
  // ... other entries ...
]);

Предварительное кэширование подресурсов страницы

Предварительное кэширование статических ресурсов, которые могут использоваться различными разделами сайта (например, JavaScript, CSS и т. д.), является общепринятой практикой и может дать дополнительный импульс в сценариях предварительной загрузки.

Чтобы ускорить навигацию на сайте электронной коммерции, вы можете использовать теги <link rel="prefetch"> на страницах листинга для предварительной загрузки страниц с подробностями о продукте для первых нескольких продуктов на странице листинга. Если вы уже предварительно кэшировали подресурсы страницы продукта, это может сделать навигацию еще быстрее.

Чтобы реализовать это:

  • Добавьте тег <link rel="prefetch"> на страницу:
 <link rel="prefetch" href="/phones/smartphone-5x.html>&quot; as="document"
  • Добавьте подресурсы страницы в список предварительного кэширования в Service Worker:
workbox.precaching.precacheAndRoute([
  '/styles/product-page.ac29.css',
  // ... other entries ...
]);

2. Продлить срок службы ресурсов предварительной выборки

Как упоминалось ранее, <link rel="prefetch"> извлекает и сохраняет ресурсы в HTTP-кэше в течение ограниченного периода времени, после чего применяются правила Cache-Control для ресурса. Начиная с Chrome 85 это значение составляет 5 минут.

Сервисные работники позволяют продлить срок службы страниц предварительной выборки, обеспечивая при этом дополнительное преимущество, заключающееся в том, что эти ресурсы доступны для использования в автономном режиме.

В предыдущем примере можно было дополнить <link rel="prefetch"> используемый для предварительной загрузки страницы продукта , стратегией кэширования во время выполнения Workbox .

Для реализации этого:

  • Добавьте тег <link rel="prefetch"> на страницу:
 <link rel="prefetch" href="/phones/smartphone-5x.html>&quot; as="document"
  • Реализуйте стратегию кэширования во время выполнения в Service Worker для следующих типов запросов:
new workbox.strategies.StaleWhileRevalidate({
  cacheName: 'document-cache',
  plugins: [
    new workbox.expiration.Plugin({
      maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
    }),
  ],
});

В этом случае мы решили использовать стратегию stale-while-revalidate . В этой стратегии страницы могут запрашиваться как из кэша, так и из сети, параллельно. Ответ поступает из кэша, если он доступен, в противном случае — из сети. Кэш всегда обновляется с помощью сетевого ответа при каждом успешном запросе.

3. Делегируйте предварительную выборку сервисному работнику

В большинстве случаев наилучшим подходом является использование <link rel="prefetch"> . Тег представляет собой подсказку ресурса , призванную сделать предварительную выборку максимально эффективной.

В некоторых случаях, однако, может быть лучше делегировать эту задачу полностью service worker. Например: для предварительной выборки первых нескольких продуктов на странице со списком продуктов, отображаемой на стороне клиента, может потребоваться динамически внедрить несколько тегов <link rel="prefetch"> на страницу на основе ответа API. Это может на мгновение занять время в основном потоке страницы и усложнить реализацию.

В таких случаях используйте "стратегию коммуникации page to service worker", чтобы полностью делегировать задачу предварительной выборки service worker. Такой тип коммуникации может быть достигнут с помощью worker.postMessage() :

Значок страницы, осуществляющей двустороннюю связь с работником сервиса.

Пакет Workbox Window упрощает этот тип коммуникации, абстрагируя многие детали выполняемого вызова.

Предварительную выборку с помощью окна Workbox можно реализовать следующим образом:

  • На странице: вызовите service worker, передав ему тип сообщения и список URL-адресов для предварительной загрузки:
const wb = new Workbox('/sw.js');
wb.register();

const prefetchResponse = await wb.messageSW({type: 'PREFETCH_URLS';, urls: []});
  • В сервис-воркере: реализуйте обработчик сообщений для выдачи запроса fetch() для каждого URL-адреса для предварительной загрузки:
addEventListener('message', (>event) = {
  if (event.data.type === 'PREFETCH_URLS') {
    // Fetch URLs and store them in the cache
  }
});