Хранилище кэша — мощный инструмент. Оно снижает зависимость ваших приложений от состояния сети. Грамотное использование кэша позволяет сделать ваше веб-приложение доступным офлайн и предоставлять ресурсы максимально быстро при любых условиях сети. Как упоминалось в разделе «Активы и данные», вы можете выбрать оптимальную стратегию кэширования необходимых ресурсов. Для управления кэшем ваш сервис-воркер взаимодействует с API хранилища кэша .
API хранилища кэша доступен из различных контекстов:
- Контекст окна (основной поток вашего PWA).
- Работник сферы услуг.
- Любые другие работники, которых вы используете.
Одно из преимуществ управления кэшем с помощью сервис-воркеров заключается в том, что его жизненный цикл не привязан к окну, то есть вы не блокируете основной поток. Имейте в виду, что для использования API хранилища кэша большинство этих контекстов должны находиться под TLS-подключением.
Что кэшировать
Первый вопрос, который может возникнуть при кэшировании, — что именно кэшировать. Хотя однозначного ответа на этот вопрос нет, вы можете начать с минимального количества ресурсов, необходимых для отображения пользовательского интерфейса.
Эти ресурсы должны включать:
- HTML-код главной страницы (start_url вашего приложения).
- Таблицы стилей CSS, необходимые для основного пользовательского интерфейса.
- Изображения, используемые в пользовательском интерфейсе.
- Файлы JavaScript, необходимые для визуализации пользовательского интерфейса.
- Данные, такие как JSON-файл, необходимые для отображения базового опыта.
- Веб-шрифты.
- В многостраничном приложении — другие HTML-документы, которые вы хотите отдать быстро или в автономном режиме.
Готово к работе в автономном режиме
Хотя поддержка офлайн-режима является одним из требований к прогрессивному веб-приложению, важно понимать, что не каждое PWA требует полноценного офлайн-режима, например, облачные игровые решения или приложения для работы с криптоактивами. Поэтому вполне допустимо предлагать базовый пользовательский интерфейс, помогающий пользователям справляться с такими ситуациями.
Ваш PWA не должен отображать сообщение об ошибке браузера о том, что веб-сервер не смог загрузить страницу. Вместо этого используйте сервис-воркер для отображения собственных сообщений, избегая стандартной и запутанной ошибки браузера.
Существует множество различных стратегий кэширования, которые вы можете использовать в зависимости от потребностей вашего PWA. Поэтому важно спроектировать использование кэша так, чтобы обеспечить быструю и надёжную работу. Например, если все ресурсы вашего приложения загружаются быстро, не занимают много места и не требуют обновления при каждом запросе, кэширование всех ресурсов будет разумной стратегией. С другой стороны, если у вас есть ресурсы, которые должны быть последней версии, возможно, стоит вообще не кэшировать эти ресурсы.
Использование API
Используйте API Cache Storage для определения набора кэшей в вашем источнике, каждый из которых идентифицируется строковым именем, которое вы можете задать. Доступ к API осуществляется через объект caches
, а метод open
позволяет создать или открыть уже созданный кэш. Метод open возвращает обещание для объекта кэша.
caches.open("pwa-assets")
.then(cache => {
// you can download and store, delete or update resources with cache arguments
});
Загрузка и хранение активов
Чтобы запросить у браузера загрузку и сохранение ресурсов, используйте методы add
или addAll
. Метод add
отправляет запрос и сохраняет один HTTP-ответ, а addAll
группу HTTP-ответов в виде транзакции, основанной на массиве запросов или URL-адресов.
caches.open("pwa-assets")
.then(cache => {
cache.add("styles.css"); // it stores only one resource
cache.addAll(["styles.css", "app.js"]); // it stores two resources
});
Интерфейс кэширования хранит весь ответ, включая заголовки и тело. Таким образом, вы можете получить его позже, используя HTTP-запрос или URL в качестве ключа. Как это сделать, описано в главе «Обслуживание» .
Когда кэшировать
В вашем PWA вы сами решаете, когда кэшировать файлы. Хотя один из подходов заключается в сохранении как можно большего количества ресурсов при установке сервис-воркера, обычно это не лучшая идея. Кэширование ненужных ресурсов приводит к нерациональному использованию полосы пропускания и дискового пространства, а также может привести к тому, что ваше приложение будет использовать устаревшие ресурсы, которые не были предусмотрены.
Вам не нужно кэшировать все активы одновременно, вы можете кэшировать активы много раз в течение жизненного цикла вашего PWA, например:
- По установке сервисного работника.
- После загрузки первой страницы.
- Когда пользователь переходит к разделу или маршруту.
- Когда сеть простаивает.
Вы можете запросить кэширование новых файлов в основном потоке или в контексте сервис-воркера.
Кэширование ресурсов в сервис-воркере
Один из наиболее распространённых сценариев — кэширование минимального набора ресурсов при установке сервис-воркера. Для этого можно использовать интерфейс кэширования в событии install
сервис-воркера.
Поскольку поток Service Worker может быть остановлен в любой момент, вы можете указать браузеру дождаться завершения выполнения addAll
, чтобы увеличить вероятность сохранения всех ресурсов и поддержания согласованности приложения. В следующем примере показано, как это сделать, используя метод waitUntil
аргумента события, полученного в прослушивателе событий Service Worker.
const urlsToCache = ["/", "app.js", "styles.css", "logo.svg"];
self.addEventListener("install", event => {
event.waitUntil(
caches.open("pwa-assets")
.then(cache => {
return cache.addAll(urlsToCache);
});
);
});
Метод waitUntil()
получает обещание и просит браузер дождаться завершения задачи из обещания (выполнения или сбоя), прежде чем завершить процесс Service Worker. Возможно, потребуется объединить обещания в цепочку и вернуть вызовы add()
или addAll()
чтобы метод waitUntil()
получал один результат.
Вы также можете обрабатывать обещания, используя синтаксис async/await. В этом случае вам необходимо создать асинхронную функцию, которая может вызывать await
и возвращать обещание в waitUntil()
после своего вызова, как в следующем примере:
const urlsToCache = ["/", "app.js", "styles.css", "logo.svg"];
self.addEventListener("install", (event) => {
let cacheUrls = async () => {
const cache = await caches.open("pwa-assets");
return cache.addAll(urlsToCache);
};
event.waitUntil(cacheUrls());
});
Междоменные запросы и непрозрачные ответы
Ваш PWA может загружать и кэшировать ресурсы из вашего источника и кросс-доменных источников, например, контент из сторонних CDN. В кросс-доменном приложении взаимодействие с кэшем очень похоже на запросы из одного источника. Запрос выполняется, и копия ответа сохраняется в вашем кэше. Как и другие кэшированные ресурсы, он доступен для использования только в источнике вашего приложения.
Ресурс будет сохранён как непрозрачный ответ , что означает, что ваш код не сможет видеть или изменять содержимое или заголовки этого ответа. Кроме того, непрозрачные ответы не отображают свой фактический размер в API хранилища, что влияет на квоты. Некоторые браузеры отображают большие объёмы, например, 7 МБ, даже если файл всего 1 КБ.
Обновление и удаление активов
Вы можете обновлять активы с помощью cache.put(request, response)
и удалять активы с помощью delete(request)
.
Более подробную информацию смотрите в документации по объекту Cache .
Отладка кэш-хранилища
Во многих браузерах есть возможность отладки содержимого кэша на вкладке «Приложение» в DevTools. Там можно увидеть содержимое каждого кэша в текущем источнике. Подробнее об этих инструментах мы расскажем в главе «Инструменты и отладка» .