Découvrez comment utiliser l'API Cache pour rendre les données de vos applications disponibles hors connexion.
L'API Cache est un système permettant de stocker et de récupérer les requêtes réseau et leurs réponses correspondantes. Il peut s'agir de requêtes et de réponses standards créées au cours de l'exécution de votre application, ou créées uniquement dans le but de stocker des données en vue d'une utilisation ultérieure.
L'API Cache a été créée pour permettre aux service workers de mettre en cache les requêtes réseau afin de fournir des réponses rapides, quelle que soit la vitesse ou la disponibilité du réseau. Cependant, l'API peut également servir de mécanisme de stockage général.
Où ce service est-il disponible ?
L'API Cache est disponible dans tous les navigateurs récents. Elle est exposée via la propriété globale caches
. Vous pouvez ainsi tester la présence de l'API avec une simple détection de caractéristiques:
const cacheAvailable = 'caches' in self;
L'API Cache est accessible depuis une fenêtre, un iFrame, un worker ou un service worker.
Que peut-on stocker ?
Les caches ne stockent que des paires d'objets Request
et Response
, représentant respectivement les requêtes et les réponses HTTP. Cependant, les requêtes et les réponses peuvent contenir tout type de données pouvant être transférées via HTTP.
Quelle quantité peut être stockée ?
En bref, beaucoup, au moins quelques centaines de mégaoctets, et potentiellement des centaines de gigaoctets ou plus. Les implémentations de navigateur varient, mais la quantité d'espace de stockage disponible dépend généralement de celle disponible sur l'appareil.
Créer et ouvrir un cache
Pour ouvrir un cache, utilisez la méthode caches.open(name)
, en transmettant le nom du cache en tant que paramètre unique. Si le cache nommé n'existe pas, il est créé. Cette méthode renvoie un Promise
qui se résout avec l'objet Cache
.
const cache = await caches.open('my-cache');
// do something with cache...
Ajout à un cache
Il existe trois façons d'ajouter un élément à un cache : add
, addAll
et put
.
Les trois méthodes renvoient un Promise
.
cache.add
Tout d'abord, il y a cache.add()
. Elle utilise un paramètre, à savoir une Request
ou une URL (string
). Elle envoie une requête au réseau et stocke la réponse dans le cache. Si la récupération échoue ou si le code d'état de la réponse n'est pas compris dans la plage 200, rien n'est stocké et Promise
rejette. Notez que les requêtes multi-origines qui ne sont pas en mode CORS ne peuvent pas être stockées, car elles renvoient un status
de type 0
. Ces requêtes ne peuvent être stockées qu'avec 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
Ensuite, il y a cache.addAll()
. Il fonctionne de la même manière que add()
, mais accepte un tableau d'objets Request
ou d'URL (string
). Cela fonctionne de la même manière que l'appel de cache.add
pour chaque requête individuelle, sauf que Promise
est refusé si une seule requête n'est pas mise en cache.
const urls = ['/weather/today.json', '/weather/tomorrow.json'];
cache.addAll(urls);
Dans chacun de ces cas, une nouvelle entrée remplace toute entrée correspondante existante. Cette méthode utilise les mêmes règles de correspondance que celles décrites dans la section sur la retrieving.
cache.put
Enfin, cache.put()
, qui vous permet de stocker une réponse du réseau, ou de créer et de stocker votre propre Response
. Elle nécessite deux paramètres. Le premier peut être un objet Request
ou une URL (string
). Le second doit être un Response
, soit à partir du réseau, soit généré par votre code.
// 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');
La méthode put()
est plus permissive que add()
ou addAll()
et vous permet de stocker des réponses non-CORS ou d'autres réponses dont le code d'état de la réponse n'est pas compris dans la plage 200. Il écrasera toutes les réponses précédentes pour la même requête.
Créer des objets Request
Créez l'objet Request
à l'aide d'une URL pour l'élément stocké:
const request = new Request('/my-data-store/item-id');
Utiliser des objets Response
Le constructeur d'objets Response
accepte de nombreux types de données, y compris les éléments Blob
, ArrayBuffer
, les objets FormData
et les chaînes.
const imageBlob = new Blob([data], {type: 'image/jpeg'});
const imageResponse = new Response(imageBlob);
const stringResponse = new Response('Hello world');
Vous pouvez définir le type MIME d'un élément Response
en définissant l'en-tête approprié.
const options = {
headers: {
'Content-Type': 'application/json'
}
}
const jsonResponse = new Response('{}', options);
Si vous avez récupéré un Response
et que vous souhaitez accéder à son corps, vous pouvez utiliser plusieurs méthodes d'assistance. Chacune renvoie un Promise
qui se résout avec une valeur d'un type différent.
Méthode | Description |
---|---|
arrayBuffer |
Renvoie un ArrayBuffer contenant le corps, sérialisé en octets.
|
blob |
Renvoie un objet Blob . Si Response a été créé avec un Blob , ce nouveau Blob aura le même type. Sinon, le Content-Type de Response est utilisé.
|
text |
Interprète les octets du corps en tant que chaîne encodée au format UTF-8. |
json |
Interprète les octets du corps en tant que chaîne encodée au format UTF-8, puis tente de l'analyser au format JSON. Renvoie l'objet résultant ou génère une exception TypeError si la chaîne ne peut pas être analysée au format JSON.
|
formData |
Interprète les octets du corps sous forme de format HTML, encodé en multipart/form-data ou en application/x-www-form-urlencoded . Renvoie un objet FormData ou génère une exception TypeError si les données ne peuvent pas être analysées.
|
body |
Renvoie un ReadableStream pour les données du corps. |
Exemple :
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]
Récupérer depuis un cache
Pour rechercher un élément dans un cache, vous pouvez utiliser la méthode match
.
const response = await cache.match(request);
console.log(request, response);
Si request
est une chaîne, le navigateur le convertit en Request
en appelant new Request(request)
. La fonction renvoie un Promise
qui se résout en Response
si une entrée correspondante est trouvée, ou undefined
dans le cas contraire.
Pour déterminer si deux Requests
correspondent, le navigateur ne se limite pas à l'URL. Deux requêtes sont considérées comme différentes si elles comportent des chaînes de requête, des en-têtes Vary
ou des méthodes HTTP différents (GET
, POST
, PUT
, etc.).
Vous pouvez ignorer tout ou partie de ces éléments en transmettant un objet options en tant que deuxième paramètre.
const options = {
ignoreSearch: true,
ignoreMethod: true,
ignoreVary: true
};
const response = await cache.match(request, options);
// do something with the response
Si plusieurs requêtes mises en cache correspondent, celle qui a été créée en premier est renvoyée. Si vous souhaitez récupérer toutes les réponses correspondantes, vous pouvez utiliser 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.`);
En guise de raccourci, vous pouvez effectuer une recherche dans tous les caches à la fois en utilisant caches.match()
au lieu d'appeler cache.match()
pour chaque cache.
Recherche en cours
L'API Cache ne permet pas de rechercher des requêtes ou des réponses, sauf pour mettre en correspondance des entrées avec un objet Response
. Toutefois, vous pouvez implémenter votre propre recherche en filtrant ou en créant un index.
Filtrage
Une façon de mettre en œuvre votre propre recherche consiste à itérer toutes les entrées et à les filtrer pour n'afficher que celles qui vous intéressent. Supposons que vous souhaitiez trouver tous les éléments dont les URL se terminent par .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;
}
De cette façon, vous pouvez utiliser n'importe quelle propriété des objets Request
et Response
pour filtrer les entrées. Notez que cela peut prendre du temps si vous effectuez une recherche sur de grands ensembles de données.
Créer un index
L'autre façon de mettre en œuvre votre propre recherche consiste à maintenir un index distinct des entrées pouvant faire l'objet d'une recherche et à stocker cet index dans IndexedDB. Comme il s'agit du type d'opération pour lequel IndexedDB a été conçu, les performances sont bien meilleures avec un grand nombre d'entrées.
Si vous stockez l'URL de Request
avec les propriétés de recherche, vous pouvez facilement récupérer l'entrée de cache appropriée après avoir effectué la recherche.
Supprimer un élément
Pour supprimer un élément d'un cache:
cache.delete(request);
Où la requête peut être une chaîne Request
ou une chaîne d'URL. Cette méthode utilise également le même objet d'options que cache.match
, ce qui vous permet de supprimer plusieurs paires Request
/Response
pour la même URL.
cache.delete('/example/file.txt', {ignoreVary: true, ignoreSearch: true});
Supprimer un cache
Pour supprimer un cache, appelez caches.delete(name)
. Cette fonction renvoie un Promise
qui résout true
si le cache existait et a été supprimé, ou false
dans le cas contraire.
Merci
Merci à Mat Scales qui a rédigé la version originale de cet article, publiée pour la première fois sur WebFundamentals.