Scopri come utilizzare l'API Cache per rendere disponibili offline i dati della tua applicazione.
L'API Cache è un sistema per l'archiviazione e il recupero delle richieste di rete e delle risposte corrispondenti. Si tratta di richieste e risposte regolari create durante l'esecuzione dell'applicazione oppure possono essere create esclusivamente per archiviare i dati per utilizzarli in un secondo momento.
L'API Cache è stata creata per consentire ai service worker di memorizzare nella cache le richieste di rete in modo da fornire risposte rapide, indipendentemente dalla velocità o dalla disponibilità della rete. Tuttavia, l'API può essere utilizzata anche come meccanismo di archiviazione generale.
Dove è disponibile?
L'API Cache è disponibile in tutti i browser moderni. Viene esposto tramite la proprietà caches
globale, in modo da poter testare la presenza dell'API con un semplice rilevamento delle funzionalità:
const cacheAvailable = 'caches' in self;
È possibile accedere all'API Cache da una finestra, un iframe, un worker o un service worker.
Che cosa può essere memorizzato
Le cache archiviano solo coppie di oggetti Request
e
Response
, che rappresentano rispettivamente richieste e risposte HTTP. Tuttavia, le richieste e le risposte possono contenere qualsiasi tipo di dati che può essere trasferito tramite HTTP.
Quanto può essere archiviato?
In breve, molti, almeno un paio di centinaia di megabyte e potenzialmente centinaia di gigabyte o più. Le implementazioni del browser variano, ma la quantità di spazio di archiviazione disponibile dipende solitamente dalla quantità di spazio di archiviazione disponibile sul dispositivo.
Creazione e apertura di una cache
Per aprire una cache, utilizza il metodo caches.open(name)
, passando il nome della cache come singolo parametro. Se la cache denominata non esiste, viene creata. Questo metodo restituisce un valore Promise
che si risolve con l'oggetto Cache
.
const cache = await caches.open('my-cache');
// do something with cache...
Aggiunta a una cache in corso...
Esistono tre modi per aggiungere un elemento a una cache: add
, addAll
e put
.
Tutti e tre i metodi restituiscono Promise
.
cache.add
Innanzitutto, c'è cache.add()
. Richiede un parametro, Request
o URL (string
). Effettua una richiesta alla rete e memorizza la risposta nella cache. Se il recupero non va a buon fine o se il codice di stato della risposta non è compreso nell'intervallo di 200, non viene archiviato nulla e Promise
lo rifiuta. Tieni presente che le richieste multiorigine non in modalità CORS non possono essere archiviate perché restituiscono status
pari a
0
. Queste richieste possono essere archiviate soltanto con 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
Poi c'è cache.addAll()
. Funziona in modo simile a add()
, ma richiede un
array di Request
oggetti o URL (string
). Questo comando funziona in modo simile alla chiamata di cache.add
per ogni singola richiesta, tranne per il fatto che Promise
viene rifiutato se una singola richiesta non viene memorizzata nella cache.
const urls = ['/weather/today.json', '/weather/tomorrow.json'];
cache.addAll(urls);
In ognuno di questi casi, una nuova voce sovrascrive qualsiasi voce esistente corrispondente. Questa operazione utilizza le stesse regole di corrispondenza descritte nella sezione sul retrieving.
cache.put
Infine, c'è cache.put()
, che consente di archiviare una risposta
dalla rete o di creare e archiviare il proprio Response
. Sono necessari due
parametri. Il primo può essere un oggetto Request
o un URL (string
).
Il secondo deve essere un Response
, proveniente dalla rete o generato dal tuo
codice.
// 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');
Il metodo put()
è più permissivo di add()
o addAll()
e
consente di archiviare risposte non CORS o altre risposte in cui il codice
di stato della risposta non è compreso nell'intervallo 200. Verranno sovrascritte tutte le risposte
precedenti per la stessa richiesta.
Creazione di oggetti richiesta
Crea l'oggetto Request
utilizzando un URL per l'elemento archiviato:
const request = new Request('/my-data-store/item-id');
Utilizzo degli oggetti Response
Il costruttore di oggetti Response
accetta molti tipi di dati, tra cui
Blob
, ArrayBuffer
, FormData
oggetti e stringhe.
const imageBlob = new Blob([data], {type: 'image/jpeg'});
const imageResponse = new Response(imageBlob);
const stringResponse = new Response('Hello world');
Puoi impostare il tipo MIME di Response
impostando l'intestazione appropriata.
const options = {
headers: {
'Content-Type': 'application/json'
}
}
const jsonResponse = new Response('{}', options);
Se hai recuperato un Response
e vuoi accedere al suo corpo, puoi utilizzare diversi metodi helper. Ciascuno restituisce un valore Promise
che si risolve
con un valore di tipo diverso.
Metodo | Descrizione |
---|---|
arrayBuffer |
Restituisce un valore ArrayBuffer contenente il corpo, serializzato in byte.
|
blob |
Restituisce un valore Blob . Se Response è stato creato
con un Blob , la nuova Blob avrà lo stesso
tipo. In caso contrario, viene utilizzato il Content-Type di
Response .
|
text |
Interpreta i byte del corpo come una stringa con codifica UTF-8. |
json |
Interpreta i byte del corpo come una stringa con codifica UTF-8, quindi tenta di analizzarla come JSON. Restituisce l'oggetto risultante o genera un valore TypeError se la stringa non può essere analizzata come JSON.
|
formData |
Interpreta i byte del corpo come un modulo HTML, codificato come
multipart/form-data o
application/x-www-form-urlencoded . Restituisce un oggetto FormData o genera un TypeError se i dati non possono essere analizzati.
|
body |
Restituisce un valore ReadableStream per i dati del corpo. |
Ad esempio:
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]
Recupero da una cache
Per trovare un elemento in una cache, puoi utilizzare il metodo match
.
const response = await cache.match(request);
console.log(request, response);
Se request
è una stringa, il browser la converte in una Request
chiamando
new Request(request)
. La funzione restituisce Promise
che si risolve in
Response
se viene trovata una voce corrispondente, o undefined
in caso contrario.
Per determinare se due Requests
corrispondono, il browser non utilizza solo l'URL. Due
richieste vengono considerate diverse se hanno stringhe di query,
intestazioni Vary
o metodi HTTP diversi (GET
, POST
, PUT
e così via).
Puoi ignorare alcune o tutte queste cose passando un oggetto opzioni come secondo parametro.
const options = {
ignoreSearch: true,
ignoreMethod: true,
ignoreVary: true
};
const response = await cache.match(request, options);
// do something with the response
Se più di una richiesta memorizzata nella cache corrisponde, la richiesta creata per prima viene restituita. Se vuoi recuperare tutte le risposte corrispondenti, puoi utilizzare
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.`);
Come scorciatoia, puoi cercare in tutte le cache contemporaneamente utilizzando caches.match()
anziché chiamare cache.match()
per ogni cache.
Ricerca in corso
L'API Cache non fornisce un modo per cercare richieste o risposte, ad eccezione delle voci corrispondenti a un oggetto Response
. Tuttavia, puoi implementare la tua ricerca utilizzando i filtri o creando un indice.
Applicazione dei filtri
Un modo per implementare la tua ricerca è eseguire l'iterazione su tutte le voci e filtrare solo quelle desiderate. Supponiamo che tu voglia trovare tutti
gli elementi il cui URL termina con .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;
}
In questo modo, puoi utilizzare qualsiasi proprietà degli oggetti Request
e Response
per filtrare le voci. Tieni presente che questo processo è lento se cerchi in grandi insiemi di dati.
Creazione di un indice
L'altro modo per implementare la propria ricerca è mantenere un indice separato di voci in cui sia possibile eseguire ricerche e archiviare l'indice in IndexedDB. Poiché questo è il tipo di operazione per cui IndexedDB è stato progettato, offre prestazioni molto migliori con un numero elevato di voci.
Se memorizzi l'URL di Request
insieme alle proprietà disponibili per la ricerca,
puoi recuperare facilmente la voce corretta della cache dopo aver effettuato la ricerca.
Eliminazione di un elemento
Per eliminare un elemento da una cache:
cache.delete(request);
Dove la richiesta può essere una stringa Request
o URL. Questo metodo utilizza anche
lo stesso oggetto opzioni di cache.match
, che ti consente di eliminare più coppie
Request
/Response
per lo stesso URL.
cache.delete('/example/file.txt', {ignoreVary: true, ignoreSearch: true});
Eliminazione di una cache
Per eliminare una cache, chiama caches.delete(name)
. Questa funzione restituisce un valore Promise
che si risolve in true
se la cache esisteva ed è stata eliminata oppure in caso contrario false
.
Grazie per aver deciso
Grazie a Mat Scales che ha scritto la versione originale di questo articolo, apparsa per la prima volta su WebFundamentals.