Dowiedz się, jak używać interfejsu Cache API, aby udostępniać dane aplikacji w trybie offline.
Interfejs Cache API to system do przechowywania i pobierania żądań sieciowych oraz odpowiadających im odpowiedzi. Mogą to być zwykłe żądania i odpowiedzi utworzone podczas działania aplikacji lub utworzone wyłącznie w celu przechowywania danych na potrzeby późniejszego wykorzystania.
Interfejs Cache API został stworzony, aby umożliwić usługom workera zapisywanie w pamięci podręcznej żądań sieciowych, dzięki czemu mogą one szybko odpowiadać niezależnie od szybkości sieci lub dostępności. Interfejsu API można jednak używać też jako ogólnego mechanizmu przechowywania.
Gdzie jest dostępna?
Interfejs Cache API jest dostępny we wszystkich nowoczesnych przeglądarkach. Jest on dostępny za pomocą właściwości globalnej caches
, dzięki czemu możesz sprawdzić obecność interfejsu API za pomocą prostego wykrywania funkcji:
const cacheAvailable = 'caches' in self;
Do interfejsu Cache API można uzyskać dostęp z poziomu okna, elementu iframe, skryptu worker lub skryptu service worker.
Co można przechowywać
Pamięci podręczne przechowują tylko pary obiektów Request
i Response
, które odpowiadają odpowiednio żądaniom i odpowiedziom HTTP. Żądania i odpowiedzi mogą jednak zawierać dowolne dane, które można przesłać przez HTTP.
Ile można przechowywać?
Krótko mówiąc, dużo, co najmniej kilkaset megabajtów, a potencjalnie nawet setki gigabajtów. Implementacje przeglądarek różnią się od siebie, ale ilość dostępnego miejsca na dane zależy zwykle od ilości miejsca dostępnej na urządzeniu.
Tworzenie i otwieranie pamięci podręcznej
Aby otworzyć pamięć podręczną, użyj metody caches.open(name)
, przekazując nazwę pamięci podręcznej jako jedyny parametr. Jeśli nazwana pamięć podręczna nie istnieje, zostanie utworzona. Ta metoda zwraca obiekt Promise
, który jest rozwiązywany w obiekcie Cache
.
const cache = await caches.open('my-cache');
// do something with cache...
Dodawanie do pamięci podręcznej
Dodanie elementu do pamięci podręcznej jest możliwe na 3 sposoby: add
, addAll
i put
.
Wszystkie 3 metody zwracają Promise
.
cache.add
Po pierwsze, cache.add()
. Przyjmuje 1 parametr: Request
lub URL (string
). Wysyła żądanie do sieci i przechowuje odpowiedź w pamięci podręcznej. Jeśli pobieranie się nie powiedzie lub kod stanu odpowiedzi nie będzie się mieścił w zakresie 200, nic nie zostanie zapisane i funkcja Promise
zostanie odrzucona. Pamiętaj, że żądań między domenami, które nie są w trybie CORS, nie można przechowywać, ponieważ zwracają one status
0
. Takie prośby można przechowywać tylko w put
.
// Retreive data.json from the server and store the response.
cache.add(new Request('/data.json'));
// Retreive data.json from the server and store the response.
cache.add('/data.json');
cache.addAll
Następnie cache.addAll()
. Działa podobnie jak add()
, ale przyjmuje tablicę obiektów Request
lub adresów URL (string
). Działa to podobnie do wywołania cache.add
w przypadku każdego żądania, z tą różnicą, że Promise
odrzuca żądanie, jeśli pojedyncze żądanie nie jest przechowywane w pamięci podręcznej.
const urls = ['/weather/today.json', '/weather/tomorrow.json'];
cache.addAll(urls);
W każdym z tych przypadków nowy wpis zastępuje wszystkie pasujące wpisy. W tym celu stosuje się te same reguły dopasowywania, które są opisane w sekcji dotyczącej pobierania.
cache.put
Ostatnim typem jest cache.put()
, który umożliwia przechowywanie odpowiedzi z sieci lub tworzenie i przechowywanie własnych cache.put()
.Response
Wymaga podania 2 parametrów. Pierwszy może być obiektem Request
lub adresem URL (string
). Drugi musi być Response
, pochodzący z sieci lub wygenerowany przez Twój kod.
// Retrieve data.json from the server and store the response.
cache.put('/data.json');
// Create a new entry for test.json and store the newly created response.
cache.put('/test.json', new Response('{"foo": "bar"}'));
// Retrieve data.json from the 3rd party site and store the response.
cache.put('https://example.com/data.json');
Metoda put()
jest bardziej liberalna niż add()
lub addAll()
i umożliwi Ci przechowywanie odpowiedzi niebędących odpowiedziami CORS lub innych odpowiedzi, których kod stanu nie mieści się w zakresie 200. Spowoduje to zastąpienie wszystkich wcześniejszych odpowiedzi na to samo żądanie.
Tworzenie obiektów żądań
Utwórz obiekt Request
, używając adresu URL rzeczy, która ma być przechowywana:
const request = new Request('/my-data-store/item-id');
Praca z obiektami odpowiedzi
Konstruktor obiektu Response
akceptuje wiele typów danych, w tym Blob
s, ArrayBuffer
s, obiekty FormData
i ciągi znaków.
const imageBlob = new Blob([data], {type: 'image/jpeg'});
const imageResponse = new Response(imageBlob);
const stringResponse = new Response('Hello world');
Typ MIME Response
możesz ustawić, ustawiając odpowiedni nagłówek.
const options = {
headers: {
'Content-Type': 'application/json'
}
}
const jsonResponse = new Response('{}', options);
Jeśli masz zwrócony obiekt Response
i chcesz uzyskać dostęp do jego treści, możesz użyć kilku metod pomocniczych. Każdy zwraca Promise
, który zwraca wartość o innym typie.
Metoda | Opis |
---|---|
arrayBuffer |
Zwraca obiekt ArrayBuffer zawierający treść sformatowaną w bajtach.
|
blob |
Zwraca wartość Blob . Jeśli Response zostało utworzone za pomocą Blob , nowe Blob będzie miało ten sam typ. W przeciwnym razie używana jest wartość Content-Type atrybutu Response .
|
text |
Interpretuje bajty w treści jako ciąg znaków zakodowany w UTF-8. |
json |
Interpretuje bajty treści jako ciąg znaków zakodowany w formacie UTF-8, a następnie próbuje przeanalizować go jako dane w formacie JSON. Zwraca obiekt wynikowy lub TypeError , jeśli nie można przetworzyć ciągu jako JSON.
|
formData |
Interpretuje bajty w treści jako formularz HTML, zakodowany jako multipart/form-data lub application/x-www-form-urlencoded . Zwraca obiekt FormData lub TypeError , jeśli nie można przeanalizować danych.
|
body |
Zwraca ReadableStream dla danych zawartych w treści. |
Przykład
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]
Pobieranie z pamięci podręcznej
Aby znaleźć element w pamięci podręcznej, możesz użyć metody match
.
const response = await cache.match(request);
console.log(request, response);
Jeśli request
to ciąg znaków, przeglądarka przekształca go w Request
, wywołując funkcję new Request(request)
. Funkcja zwraca wartość Promise
, która jest interpretowana jako Response
, jeśli zostanie znaleziony pasujący wpis, lub undefined
w przeciwnym razie.
Aby określić, czy 2 wartości Requests
są takie same, przeglądarka korzysta z czegoś więcej niż tylko adresu URL. Dwa żądania są uważane za różne, jeśli mają różne ciągi znaków zapytania, nagłówki Vary
lub metody HTTP (GET
, POST
, PUT
itp.).
Możesz zignorować niektóre z tych elementów lub wszystkie, przekazując obiekt opcji jako drugi parametr.
const options = {
ignoreSearch: true,
ignoreMethod: true,
ignoreVary: true
};
const response = await cache.match(request, options);
// do something with the response
Jeśli dopasowanie dotyczy więcej niż 1 żądania w pamięci podręcznej, zwracane jest to, które zostało utworzone jako pierwsze. Jeśli chcesz pobrać wszystkie pasujące odpowiedzi, możesz użyć elementu 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.`);
Jako skrót możesz przeszukać wszystkie pamięci podręczne naraz, używając funkcji caches.match()
zamiast wywoływać funkcję cache.match()
dla każdej pamięci podręcznej.
Szukam
Interfejs Cache API nie umożliwia wyszukiwania żądań ani odpowiedzi, z wyjątkiem dopasowania wpisów do obiektu Response
. Możesz jednak zaimplementować własne wyszukiwanie, stosując filtrowanie lub tworząc indeks.
Filtrowanie
Jednym ze sposobów wdrożenia własnego wyszukiwania jest przejrzenie wszystkich wpisów i wyfiltrowanie tych, które Cię interesują. Załóżmy, że chcesz znaleźć wszystkie elementy, których adresy URL kończą się na .png
.
async function findImages() {
// Get a list of all of the caches for this origin
const cacheNames = await caches.keys();
const result = [];
for (const name of cacheNames) {
// Open the cache
const cache = await caches.open(name);
// Get a list of entries. Each item is a Request object
for (const request of await cache.keys()) {
// If the request URL matches, add the response to the result
if (request.url.endsWith('.png')) {
result.push(await cache.match(request));
}
}
}
return result;
}
W ten sposób możesz użyć dowolnej właściwości obiektów Request
i Response
, aby filtrować wpisy. Pamiętaj, że w przypadku wyszukiwania dużych zbiorów danych proces może być powolny.
Tworzenie indeksu
Innym sposobem na wdrożenie własnego wyszukiwania jest prowadzenie osobnego indeksu wpisów, które można wyszukiwać, i przechowywanie tego indeksu w IndexedDB. Ponieważ IndexedDB został zaprojektowany do tego typu operacji, jego wydajność jest znacznie lepsza w przypadku dużej liczby wpisów.
Jeśli przechowujesz adres URL Request
obok właściwości wyszukiwalnych, możesz łatwo pobrać odpowiedni wpis w pamięci podręcznej po przeprowadzeniu wyszukiwania.
Usuwanie elementu
Aby usunąć element z pamięci podręcznej:
cache.delete(request);
Gdzie request może być Request
lub ciągiem znaków adresu URL. Ta metoda przyjmuje ten sam obiekt opcji co cache.match
, co pozwala usuwać wiele par Request
/Response
dla tego samego adresu URL.
cache.delete('/example/file.txt', {ignoreVary: true, ignoreSearch: true});
Usuwanie pamięci podręcznej
Aby usunąć pamięć podręczną, wywołaj funkcję caches.delete(name)
. Ta funkcja zwraca wartość Promise
, która jest równa true
, jeśli pamięć podręczna istniała i została usunięta, lub false
w przeciwnym razie.
Dziękujemy
Dziękujemy Matowi Scalesowi, który napisał pierwotną wersję tego artykułu, który po raz pierwszy pojawił się na stronie WebFundamentals.