#05 — Заставьте прогрессивные веб-приложения работать в автономном режиме

Добро пожаловать на пятый день #30DaysOfPWA! Новичок в серии? Три вещи, которые вы можете сделать, чтобы наверстать упущенное:

  • Прочитайте начальный пост ниже, чтобы понять контекст.
  • Следите за обновлениями в репозитории GitHub.
  • Добавьте блог #30DaysOfPWA в закладки для ресурсов.

Добро пожаловать на #30DaysOfPWA

Nitya Narasimhan, Ph.D. для Microsoft Azure ・ Feb 14 ・ 2 min read

#pwa #pwabuilder #webdev #новички

Это сокращенная версия канонического поста для #30DaysOfPWA.


О чем мы расскажем сегодня

  • Что означает офлайн для PWA?
  • Как PWA узнает об изменениях в сети?
  • К каким вариантам хранения данных могут обращаться работники служб?
  • Какие стратегии кэширования могут использовать PWA?
  • Упражнение: Исследуйте автономный опыт в примерах PWA

Подведем итоги

В предыдущем посте мы узнали, что Service Workers — это тип веб-рабочего, который действует как сетевой прокси (перехватывая запросы на получение), разумно управляет хранением кэша (для автономной работы) и обрабатывает асинхронные события, такие как push-уведомления (для поддержки повторно подключаемого поведения). Мы узнали о регистрации Service Worker и событиях жизненного цикла, которые приводят к его активации.

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


Что означает «автономный»?

Ключевое различие между нативным (установленным) и веб-опытом (в браузере) традиционно заключается в зависимости от сети. Обычные веб-сайты не будут надежно работать, если вы находитесь вне сети (например, в режиме полета) или имеете плохое подключение к сети (в транзите или регионах с низкой пропускной способностью).

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

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

Теперь, когда работники служб перехватывают запрос «fetch», они могут оценить различные стратегии возврата ответа. Например: стратегия «сначала офлайн» может агрессивно отдавать предпочтение кэшу перед сетью при возврате ответов. Хотя это может принести преимущества в производительности (уменьшение сетевых задержек), это также требует управления приоритетами элементов кэша для воздействия.

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

Но сначала уделите минутку, чтобы просмотреть выбранный вами образец PWA и посмотреть на реализацию его сервисного работника. Держите его открытым в одной вкладке, чтобы вы могли изучить его в контексте данного обсуждения. Я использую DevTools Tips и сделал копию его файла sw.js в этом gist для справки.


Понимание параметров хранения

Чтобы сделать ресурсы доступными в автономном режиме, необходимо использовать преимущества хранения данных на устройстве. Учитывая их асинхронную природу, работники сервисов (веб-работники) имеют доступ к двум вариантам:

  • CacheStorage — API для хранения именованных объектов Cache, к которым могут обращаться как работники сервисов, так и основной поток JavaScript приложения. Кэши хранят пары запрос/ответ для сетевых ресурсов. Кэшами нужно управлять явно — для обновлений и удалений — с квотами, установленными для каждого источника. При необходимости рабочий сервис может иметь несколько именованных объектов Cache.
  • IndexedDB — API для хранения больших объемов структурированных данных, включая файлы и блобы. Это объектно-ориентированная транзакционная база данных, которая использует пары ключ-значение и идеально подходит для хранения отдельных активов (по сравнению со страницами ответов в кэше). Подробнее об IndexedDB вы можете прочитать на неделе 4 «Платформы и практика».

Обратите внимание, что опции Web Storage (localStorage и sessionStorage) являются синхронными и не могут быть использованы в веб-рабочих — но вы можете использовать их из главного потока с потенциальным снижением производительности. Подробнее об этом здесь. Хотите получить более полное представление о возможностях хранения данных? Просто просмотрите панель приложений PWA с помощью DevTools и отлаживайте в интерактивном режиме.

Ознакомьтесь с документацией Microsoft Edge для панелей Service Workers, Cache Storage и IndexedDB, чтобы узнать, как исследовать их в реальном контексте.


Хранение кэша и стратегии

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

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

Давайте рассмотрим несколько стратегий, используя код из примера PWA.

1. Кэширование при установке для повышения производительности

Вот соответствующий фрагмент кода из гиста DevTools Tips sw.js, аннотированный моими комментариями для ясности


// named cache in Cache Storage
const CACHE_NAME = 'devtools-tips-v3';

// list of requests whose responses will be pre-cached at install
const INITIAL_CACHED_RESOURCES = [
    '/',
    '/offline/',
    '/all/',
    '/browser/edge/',
    '/browser/safari/',
    '/browser/firefox/',
    '/browser/chrome/',
    '/assets/style.css',
    '/assets/filter-tip-list.js',
    '/assets/share.js',
    '/assets/logo.png',
    'https://unpkg.com/prismjs@1.20.0/themes/prism-okaidia.css',
    '/assets/localforage-1.10.0.min.js'
];

// install event handler (note async operation)
// opens named cache, pre-caches identified resources above
self.addEventListener('install', event => {
    event.waitUntil((async () => {
        const cache = await caches.open(CACHE_NAME);
        cache.addAll(INITIAL_CACHED_RESOURCES);
    })());
});
Войти в полноэкранный режим Выход из полноэкранного режима

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

2. Кэш-первый при (выборке) извлечении

Теперь, когда получено событие выборки, работник службы может применить свою предпочтительную политику — здесь стратегия «сначала кэш» означает, что работник службы ищет соответствие в кэше и обращается к сети только в случае промаха. Обратите внимание, что вы можете предварительно отфильтровать параметры запроса для уточнения политики — например, обращаться к кэшу, только если тип ресурса — HTML-страница и т.д.

Вот соответствующий фрагмент из нашего примера PWA.


// We have a cache-first strategy, 
// where we look for resources in the cache first
// and only on the network if this fails.
self.addEventListener('fetch', event => {
    event.respondWith((async () => {
        const cache = await caches.open(CACHE_NAME);

        // Try the cache first.
        const cachedResponse = await cache.match(event.request);
        if (cachedResponse !== undefined) {
            // Cache hit, let's send the cached resource.
            return cachedResponse;
        } else {
            // Nothing in cache, let's go to the network.

            // ...... truncated ....
        }
    }
}
Войти в полноэкранный режим Выход из полноэкранного режима

Обнаружение изменений в сети

В приведенных выше примерах были показаны сценарии, в которых политика кэширования не зависит от состояния сети (т.е. всегда сначала проверяется кэш). Но что если вы хотите обусловить свою стратегию текущим состоянием сети?

Свойство navigator.onLine возвращает булево значение (true/false), отражающее сетевой статус браузера. Разные браузеры могут реализовывать это свойство по-разному — поэтому вы можете захотеть разобраться в нюансах, чтобы избежать ложных срабатываний и отрицательных результатов. Свойство должно посылать события обновления, если этот статус меняется — и вы можете прослушивать эти события на уровне window.

window.addEventListener("online",  function(){
    console.log("You are online!");
});
window.addEventListener("offline", function(){
    console.log("Oh no, you lost your network connection.");
});
Вход в полноэкранный режим Выход из полноэкранного режима

Как же этот слушатель событий может уведомить Service Worker об изменении сети? Работники служб и их клиенты могут взаимодействовать с помощью API postMessage. На стороне клиента это означает отправку сообщения с соответствующими данными:

navigator.serviceWorker.controller.postMessage({ 
   type: `IS_OFFLINE`
   // add more properties if needed
});
Вход в полноэкранный режим Выход из полноэкранного режима

На стороне работника службы он прослушивает события «сообщение» и распаковывает данные для дальнейших действий:

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'IS_OFFLINE') {
    // take relevant actions
  }
});
Вход в полноэкранный режим Выход из полноэкранного режима

Вы также можете использовать свойство navigator.connection для доступа к информации о качестве сети. К ним относятся:

  • navigator.connection.downlink для получения оценки эффективной пропускной способности (если доступно)
  • navigator.connection.saveData, если пользователь активировал опцию «сохранить данные» в своем браузере.

Визуальная сводка

Service Workers могут делать и другие вещи — например, обрабатывать push-уведомления или получать данные в фоновом режиме и использовать их для обновления приложения или кэша для повышения эффективности. Ищите материалы на неделе 4 (Платформы и практика), которые могут быть уместны в контексте.

Это было довольно много, верно? Надеюсь, это визуальное резюме (все, о чем мы говорили в Service Workers, вариантах хранения и стратегиях кэширования) поможет вам просмотреть и вспомнить ключевые элементы.


Учебные ресурсы

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

  • Поддержка современных браузеров | Такие сайты, как caniuse.com и «Готов ли Service Worker?», предоставляют легко читаемые информационные панели, показывающие степень поддержки определенных API и функций Service Worker в различных браузерах.
  • API Service Worker | Этот ресурс MDN хорошо освещает интерфейсы Service Worker, случаи использования и связанные API.
  • Опции хранения данных | Узнайте больше об API Cache Storage, API Cache и API IndexedDB — чтобы понять, какие типы данных поддерживает каждый из них и как их можно использовать в рабочих службах.
  • Workbox | Эти библиотеки, разработанные Google, обеспечивают работу рабочих служб, готовых к производству, и описывают общие рецепты стратегий кэширования, которые можно использовать в PWA.

Следите за материалами в следующие недели, в которых некоторые из этих тем будут рассмотрены более подробно.


Упражнение: Ваша очередь!!!

Вы знаете, как это делается! Выберите образец PWA и просмотрите его в браузере DevTools.

  • Откройте панель Service Worker и просмотрите файл реализации.
  • Найдите обработчик события установки — соотнесите его с содержимым кэша. Было ли что-нибудь предварительно кэшировано при запуске?
  • Найдите обработчик события fetch — какую стратегию кэширования применяет PWA?
  • Переключите режим «Offline» в панели DevTools Service Worker. Перейдите на разные страницы приложения. Что вы видите?
    • Получаете ли вы пользовательскую автономную страницу для некэшированных активов?
    • Получаете ли вы действительные страницы при переходе к предварительно кэшированным маршрутам?
  • Просмотрите остальную часть реализации service worker — постарайтесь понять, какие события он обрабатывает и как они влияют на стратегии кэширования и поведение в автономном режиме.

Хотите прочитать больше материалов от технологов Microsoft? Не забудьте следить за Azure прямо здесь, на dev.to:

Microsoft Azure

Любой язык. Любая платформа.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *