Skip to content
О сайте Блог Обучение Исследовать узоры Case studies
Содержание
  • Где он доступен?
  • Какие данные в нем можно хранить
    • Какой объем данных можно хранить?
  • Создание и открытие кеша
  • Добавление записи в кеш
    • cache.add
    • cache.addAll
    • cache.put
  • Извлечение записей из кеша
  • Поиск
    • Фильтрация
    • Создание индекса
  • Удаление записи
  • Удаление кеша
  • Благодарности
  • Home
  • All articles

Cache API: краткое руководство

Узнайте, как сделать данные приложения доступными в офлайн-режиме при помощи Cache API.

Oct 3, 2017 — Обновлено Apr 27, 2020
Available in: English, 日本語 и 한국어
Appears in: Надежность соединения
Pete LePage
Pete LePage
TwitterGitHubGlitchHomepage
Содержание
  • Где он доступен?
  • Какие данные в нем можно хранить
    • Какой объем данных можно хранить?
  • Создание и открытие кеша
  • Добавление записи в кеш
    • cache.add
    • cache.addAll
    • cache.put
  • Извлечение записей из кеша
  • Поиск
    • Фильтрация
    • Создание индекса
  • Удаление записи
  • Удаление кеша
  • Благодарности

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

Cache API был создан, чтобы позволить сервис-воркерам кешировать сетевые запросы и тем самым обеспечивать быстрое время ответа вне зависимости от скорости и доступности сетевого подключения. Однако этот API можно использовать в качестве механизма хранения данных общего назначения.

Где он доступен? #

Cache API доступен во всех современных браузерах. Доступ к нему осуществляется через глобальное свойство caches, поэтому проверить наличие API очень просто:

const cacheAvailable = 'caches' in self;

Доступ к Cache API можно получить из окна, элемента iframe, веб-воркера или сервис-воркера.

Какие данные в нем можно хранить #

В кеше могут храниться только пары объектов Request и Response, представляющих HTTP-запросы и ответы соответственно. Однако запросы и ответы могут содержать любые данные, которые можно передавать по HTTP.

Какой объем данных можно хранить? #

Большой: как минимум пару сотен мегабайт, а в теории — сотни гигабайт или больше. Реализации в браузерах различаются, однако объем, доступный для хранения данных, обычно зависит от объема памяти устройства.

Создание и открытие кеша #

Чтобы открыть кеш, используйте метод caches.open(name), указав в качестве единственного параметра название кеша. Если кеша с таким названием не существует, он будет создан. Метод возвращает обещание (Promise), которое разрешается в объект Cache.

const cache = await caches.open('my-cache');
// далее выполняем операции с объектом cache...

Добавление записи в кеш #

Для добавления записи в кеш существуют три метода: add, addAll и put. Все три метода возвращают Promise.

cache.add #

Первый метод — это cache.add(). Он принимает один параметр: либо объект Request, либо URL-адрес (в виде строки). Метод инициирует сетевой запрос и сохраняет в кеше ответ на него. Если загрузка завершается неудачно или код ответа лежит за пределами диапазона 200, то ответ не сохраняется, а Promise будет отклонен. Обратите внимание, что запросы между различными источниками, выполненные не в режиме CORS, не будут сохранены, поскольку возвращают status 0. Такие запросы можно сохранять только при помощи метода put.

// Загружаем с сервера data.json и сохраняем ответ.
cache.add(new Request('/data.json'));

// Загружаем с сервера data.json и сохраняем ответ.
cache.add('/data.json');

cache.addAll #

Следующий метод — cache.addAll(). Он работает аналогично add(), но принимает массив объектов Request или URL-адресов (в виде строк). Вызов этого метода идентичен вызову cache.add для каждого запроса по отдельности, с тем исключением, что Promise будет отклонен в случае неудачного завершения любого из запросов.

const urls = ['/weather/today.json', '/weather/tomorrow.json'];
cache.addAll(urls);

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

cache.put #

Последний метод — cache.put(), при помощи которого можно как сохранить ответ из сети, так и создать и сохранить свой собственный объект Response. Метод принимает два параметра. Первый параметр — либо объект Request, либо URL-адрес (в виде строки). Второй параметр — объект Response (либо полученный из сети, либо сгенерированный вашим собственным кодом).

// Получаем data.json с сервера и сохраняем ответ.
cache.put('/data.json');

// Создаем новую запись для test.json и сохраняем свежесозданный ответ.
cache.put('/test.json', new Response('{"foo": "bar"}'));

// Скачиваем data.json со стороннего сайта и сохраняем ответ.
cache.put('https://example.com/data.json');

Метод put() имеет менее строгие ограничения, чем add() или addAll(), и позволяет сохранять ответы, полученные не в режиме CORS, а также иные ответы с кодом состояния за пределами диапазона 200. Он перезаписывает любые предыдущие ответы на аналогичный запрос.

Создание объектов Request #

При создании объекта Request в качестве аргумента указывается URL-адрес сохраняемого ресурса:

const request = new Request('/my-data-store/item-id');

Работа с объектами Response #

Конструктор объекта Response принимает множество типов данных, включая Blob, ArrayBuffer, FormData и строки.

const imageBlob = new Blob([data], {type: 'image/jpeg'});
const imageResponse = new Response(imageBlob);
const stringResponse = new Response('Hello world');

MIME-тип объекта Response устанавливается путем установки соответствующего заголовка.

  const options = {
headers: {
'Content-Type': 'application/json'
}
}
const jsonResponse = new Response('{}', options);

Если вы извлекли объект Response и хотите получить доступ к его телу, для этого существует ряд вспомогательных методов. Каждый метод возвращает Promise, который разрешается в значение соответствующего типа.

МетодОписание
arrayBufferВозвращает объект ArrayBuffer с телом, сериализованным в байты.
blobВозвращает объект Blob. Если объект Response был создан с объектом Blob, то новый объект Blob будет иметь тот же тип. В противном случае используется заголовок Content-Type объекта Response.
textИнтерпретирует байты тела как строку в кодировке UTF-8.
jsonИнтерпретирует байты тела как строку в кодировке UTF-8, а затем пытается обработать ее как JSON. Возвращает получившийся в результате объект или выдает ошибку TypeError, если строку не удается обработать как JSON.
formDataИнтерпретирует байты тела как HTML-форму, закодированную в формате multipart/form-data или application/x-www-form-urlencoded. Возвращает объект FormData или, если данные не удается обработать, выдает ошибку TypeError.
bodyВозвращает объект ReadableStream для чтения данных тела.

Пример:

const response = new Response('Hello world');
const buffer = await response.arrayBuffer();
console.log(new Uint8Array(buffer));
// Uint8Array(11) [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]

Извлечение записей из кеша #

Для поиска записи в кеше можно использовать метод match.

const response = await cache.match(request);
console.log(request, response);

Если параметр request является строкой, браузер преобразует его в объект Request при помощи вызова new Request(request). Функция возвращает Promise, который в случае обнаружения подходящей записи разрешается в объект Response, а в противном случае — в undefined.

При сравнении двух объектов Request браузер учитывает не только URL-адрес. Объекты Request считаются несовпадающими, если у них различаются строки запроса, заголовки Vary или методы HTTP (GET, POST, PUT и т. д.).

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

const options = {
ignoreSearch: true,
ignoreMethod: true,
ignoreVary: true
};

const response = await cache.match(request, options);
// обработка ответа

Если найдено более одного кешированного запроса, то будет возвращен запрос, который был создан раньше всего. Если вам нужно извлечь все запросы, соответствующие критериям, используйте метод cache.matchAll().

const options = {
ignoreSearch: true,
ignoreMethod: true,
ignoreVary: true
};

const responses = await cache.matchAll(request, options);
console.log(`There are ${responses.length} matching responses.`);

Чтобы сократить объем кода, для поиска по всем кешам сразу можно использовать caches.match(), вместо того чтобы вызывать cache.match() для каждого отдельного кеша.

Поиск #

Cache API не позволяет искать запросы или ответы каким-либо образом, кроме сравнения записей с объектом Response. Однако возможность поиска можно реализовать самостоятельно, используя фильтрацию или индексирование.

Фильтрация #

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

async function findImages() {
// Получаем список всех кешей для текущего источника
const cacheNames = await caches.keys();
const result = [];

for (const name of cacheNames) {
// Открываем кеш
const cache = await caches.open(name);

// Получаем список записей. Каждая запись — объект Request
for (const request of await cache.keys()) {
// Если URL-адрес запроса совпадает, добавляем ответ к результату
if (request.url.endsWith('.png')) {
result.push(await cache.match(request));
}
}
}

return result;
}

Таким образом вы можете использовать для фильтрации записей любое свойство объектов Request и Response. Обратите внимание, что на больших массивах данных поиск будет медленным.

Создание индекса #

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

Если URL-адрес объекта Request будет храниться вместе со свойствами, используемыми для поиска, вы сможете легко находить нужную запись в кеше и извлекать ее.

Удаление записи #

Удалить запись из кеша можно следующим образом:

cache.delete(request);

Параметр request — это либо объект Request, либо URL-адрес в виде строки. Этот метод также принимает объект option с теми же параметрами, что и для метода cache.match, благодаря чему его можно использовать для удаления сразу нескольких пар Request/Response, соответствующих одному и тому же URL-адресу.

cache.delete('/example/file.txt', {ignoreVary: true, ignoreSearch: true});

Удаление кеша #

Чтобы удалить кеш, используйте caches.delete(name). Функция возвращает Promise, который разрешается в true, если кеш существовал и был удален, или в false в противном случае.

Благодарности #

Спасибо Мэту Скейлсу за написание оригинальной версии этой статьи, впервые опубликованной на WebFundamentals.

Прогрессивные веб-приложения
Последнее обновление: Apr 27, 2020 — Улучшить статью
Return to all articles
Поделиться
подписаться

Contribute

  • Сообщить об ошибке
  • Просмотреть исходный код

Дополнительная информация

  • developer.chrome.com
  • Новости Chrome
  • Разборы конкретных случаев
  • Подкасты
  • Шоу

Соцсети

  • Twitter
  • YouTube
  • Google Developers
  • Chrome
  • Firebase
  • Google Cloud Platform
  • Все продукты
  • Условия и конфиденциальность
  • Правила сообщества

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies.