Кэширование данных вашего приложения¶
Добро пожаловать на неделю 2 день 5 из серии 30 Days of PWA! В сегодняшней статье мы расскажем вам о том, как стать более эффективным и организованным в вопросах кэширования.
Начнем с краткого обзора кэширования в PWA, который Nitya представила в четвертый день...
Основы кэширования¶
Прогрессивные веб-приложения имеют большой контроль над тем, как они управляют загрузкой ресурсов. В значительной степени это возможно благодаря сервис-воркерам, которые имеют возможность перехватывать, манипулировать и отвечать непосредственно на сетевые запросы. В дополнение к этому Cache API позволяет сервису-воркеру хранить и извлекать ранее полученные (или созданные) объекты Response, что дает возможность не обращаться к сети для получения долгоживущих ресурсов, таких как таблицы стилей и изображения.
Прежде чем приступить к работе, хочу отметить, что Cache API доступен везде, а не только в рамках сервис-воркера. Если вы используете его только в контексте сервис-воркера, то он гарантированно будет доступен, но если вы используете его в других местах, то вам необходимо протестировать, чтобы убедиться в доступности этой функции:
1 2 3 |
|
Вот краткая информация о том, как работает Cache API. Следует помнить, что он основан на промисе. Начнем с создания/открытия кэша:
1 |
|
В результате будет создан кэш app
, если он еще не существует, и затем он будет открыт. Затем вы можете добавлять элементы в кэш с помощью функций add()
, addAll()
или put()
. Вот краткое описание того, как они работают:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Довольно круто, правда? Теперь, когда элементы находятся в кэше, их можно извлечь, используя match()
:
1 2 3 |
|
Обычно это делается в контексте события Fetch
в сервисе-воркере, но можно использовать и в основном потоке для выполнения таких действий, как заполнение автономной страницы списком страниц, находящихся в кэше. Довольно интересная вещь.
И наконец, в завершение, вы можете удалять элементы из кэша так же легко, как и добавлять их:
1 |
|
С предварительными вопросами покончено, давайте рассмотрим, как управлять кэшированными данными.
Наведение порядка¶
В кэше браузера можно хранить большое количество данных — в некоторых случаях гигабайты. Однако то, что мы можем это делать, не означает, что мы должны это делать. В конце концов, в определенный момент браузер вытеснит из памяти весь сайт, если места станет мало. Лучше не быть "загонщиком" ресурсов, когда они придут очищать пространство 😉.
Прежде чем мы начнем более тщательно подходить к выбору объема кэшируемых данных, необходимо разделить их на категории. Например, в PWA будет содержаться более долгоживущий контент, такой как CSS, JavaScript, логотип сайта и, возможно, ваша автономная страница. Я предпочитаю рассматривать их как ресурсы и создаю для них специальный кэш. Аналогичным образом, скорее всего, вы будете кэшировать запросы для других категорий содержимого, таких как страницы, изображения и т.д. Мне нравится определять эти категории как отдельные кэши, чтобы можно было добавлять в них элементы и удалять из них более целенаправленно. Я определяю их в верхней части своего сервис-воркера:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Здесь видно, что я использую переменную для отслеживания version
моего кэша. Версионность кэша — это лучшая практика, поскольку она позволяет полностью удалять старые (устаревшие) кэши при отправке новых версий долгоживущих ресурсов (обычно в событии "активация" сервис-воркера).
После определения префикса версии я создал объект для определения различных кэшей, с которыми буду работать: ресурсов, изображений и страниц. Создание каждого объекта может показаться излишеством, но на это есть свои причины, о которых я расскажу вкратце.
С помощью этой настройки я могу использовать событие сервис-воркера install
для кэширования своих ресурсов:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Здесь я определил URL-адрес своей автономной страницы (offline_page
) отдельно, поскольку ссылаюсь на эту строку в другом месте сервис-воркера. Затем я включил этот URL вместе с favicon моего PWA, а также его основными CSS и JavaScript в preinstall
, который, в свою очередь, попадает в cache.addAll()
как часть события сервис-воркера install
. Поскольку Cache API основан на промисах, можно видеть, что событие install
(event
) запрашивается для ожидания открытия соответствующего кэша (в данном случае sw_caches.assets.name
) и завершения операции addAll()
.
Мы можем использовать эту организацию и в событии fetch
. Обычно я использую различные рецепты кэша/сети для разных типов ресурсов. Аналогично, я могу хранить любой из этих ресурсов в наиболее подходящем кэше. Вот сокращенный пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Это очень упрощенный пример, но вы можете видеть, как использовать информацию о запросе для принятия решений о том, куда сначала обращаться — в кэш или в сеть, и где хранить копии запроса.
Теперь, правда, вы можете искать совпадения сразу во всех кэшах вашего PWA, используя caches.match()
, в отличие от открытия и поиска в конкретном, именованном кэше. Поэтому вы можете задаться вопросом, почему я рекомендую поддерживать разные кэши. Вот почему: Это позволяет нам более целенаправленно подходить к очистке кэшированных ресурсов.
Уборка за собой¶
Когда Нити рассказывала о жизненном цикле сервис-воркера в первой неделе, она упомянула событие activate
. Активация — это отличное время для очистки устаревших кэшей. Обычно это обсуждается в контексте истечения срока действия старого кэшированного содержимого путем проверки, не совпадают ли имена кэшей с текущим значением version
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Этот код собирает все ключи (имена) кэша, созданные в PWA. Затем он отфильтровывает их до тех, которые не начинаются с текущего значения version
, и затем удаляет их. Это очень жесткий способ удаления кэшированных ресурсов, но он отлично подходит для тех случаев, когда вы хотите очистить все, потому что хотите начать с чистого листа (на что и указывает изменение version
).
Когда вы начнете разделять свои кэши на несколько частей, вы также сможете установить ограничения на количество ресурсов, которые вы хотите держать под рукой. Некоторые кэши, например, ресурсы, вы, вероятно, захотите хранить в течение длительного времени. Другие кэши, возможно, следует ограничить определенным количеством ресурсов. Давайте настроим sw_caches
для этого:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Здесь я установил жесткие ограничения на количество элементов в кэше изображений и страниц (50 и 10 соответственно). Установив эти ограничения, мы можем создать более методичную утилиту для обрезки кэша:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Эта функция принимает два аргумента: имя кэша (cache_name
) и максимальное количество элементов, которое мы хотим вместить в кэш (limit
). Вот что она делает:
- Открывает именованный кэш (
caches.open()
), затем - Получить элементы в кэше (
cache.keys()
), затем - Проверить, не превышает ли количество элементов установленный лимит,
- Если превышает, то определить, сколько элементов нужно удалить, и (наконец)
- Удалить излишки, начиная с первого (самого старого) элемента.
Эта функция может быть вызвана в любое время, но я часто запускаю ее при загрузке страницы, вызывая из главного потока:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Первый блок этого фрагмента находится в моем основном файле JavaScript, сразу после регистрации сервис-воркера. Он проверяет, существует ли контроллер сервис-воркера, и, если существует, отправляет ему команду "очистить" через postMessage()
. Второй блок, показанный здесь, находится в файле сервис-воркера и прослушивает входящие сообщения. Получив сообщение "clean up", он просматривает список определенных мною кэшей и запускает функцию trimCache()
для всех, у которых есть limit
.
Попробуйте¶
Cache API — это невероятно мощный инструмент, и в этой заметке мы лишь поверхностно рассмотрим его возможности. Поиграйте с ним и найдите те подходы, которые работают лучше всего для вас. Помните, что они будут отличаться от проекта к проекту и от ресурса к ресурсу. Оставайтесь гибкими и думайте о том, какие стратегии кэширования имеют наибольший смысл. Также не бойтесь передумать; вы всегда можете пересмотреть version
и начать все с нуля.
Настройтесь на завтрашний выпуск следующего поста, в котором мы рассмотрим множество вариантов синхронизации данных с помощью сервис-воркера.
Ресурсы¶
- API сервис-воркера (MDN)
- Использование сервисов-воркеров для управления сетевыми запросами и push-уведомлениями ("Документация для разработчиков Edge")