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ł utworzony, aby umożliwić mechanizmom Service Worker buforowanie żądań sieciowych, co pozwala na szybkie udzielanie odpowiedzi niezależnie od szybkości sieci i 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 ujawniany za pomocą globalnej właściwości caches
, więc możesz przetestować obecność interfejsu API za pomocą prostego wykrywania funkcji:
const cacheAvailable = 'caches' in self;
Interfejs Cache API jest dostępny z poziomu okna, elementu iframe, instancji roboczej 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 jeden parametr: Request
lub adres URL (string
). Wysyła żądanie do sieci i zapisuje odpowiedź w pamięci podręcznej. Jeśli pobieranie nie powiedzie się lub jeśli kod stanu odpowiedzi nie mieści się w zakresie 200, nic nie jest zapisywane, a Promise
odrzuca. 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 funkcji cache.add
w przypadku każdego pojedynczego żądania, z tym wyjątkiem, że funkcja 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ąpi dowolny pasujący istniejący wpis. 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()
. Potrzeba 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
, korzystając z adresu URL przechowywanej rzeczy:
const request = new Request('/my-data-store/item-id');
Praca z obiektami odpowiedzi
Konstruktor obiektów Response
akceptuje wiele typów danych, w tym obiekty Blob
, ArrayBuffer
, FormData
i ciągi tekstowe.
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 postaci bajtów.
|
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 polu tekstowym jako ciąg znaków zakodowany w UTF-8. |
json |
Interpretuje bajty treści jako ciąg zakodowany w formacie UTF-8, a następnie próbuje przeanalizować go jako 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ą uznawane za różne, jeśli mają różne ciągi zapytań, nagłówki Vary
lub metody HTTP (GET
, POST
, PUT
itp.).
Możesz zignorować niektóre lub wszystkie z tych elementów, przekazując obiekt options 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 występuje w przypadku 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 wdrożyć 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 odfiltrowanie 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 implementacji własnego wyszukiwania jest utrzymanie osobnego indeksu wpisów, które można przeszukiwać i przechowywać w IndexedDB. IndexedDB został zaprojektowany z myślą o takim rodzaju operacjach, dlatego 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.