Découvrez comment utiliser l'API Cache pour rendre les données de votre application 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 régulières créées lors de l'exécution de votre application, ou elles peuvent être créées uniquement dans le but de stocker des données pour une utilisation ultérieure.
L'API Cache a été créée pour permettre aux services workers de mettre en cache les requêtes réseau afin de pouvoir 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 modernes. 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;
Vous pouvez accéder à l'API Cache depuis une fenêtre, un iframe, un nœud de calcul ou un service worker.
Données pouvant être stockées
Les caches ne stockent que des paires d'objets Request
et Response
, représentant respectivement les requêtes et les réponses HTTP. Toutefois, les requêtes et les réponses peuvent contenir n'importe quel 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 la quantité d'espace de stockage 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 comme 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...
Ajouter à 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 accepte un paramètre, soit un Request
, soit 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 ne se situe pas dans la plage 200, rien n'est stocké et Promise
est rejeté. Notez que les requêtes inter-origines qui ne sont pas en mode CORS ne peuvent pas être stockées, car elles renvoient un status
de 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
rejette toute requête individuelle qui 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. Les mêmes règles de correspondance que celles décrites dans la section sur la récupération sont appliquées.
cache.put
Enfin, il existe cache.put()
, qui vous permet de stocker une réponse du réseau ou de créer et de stocker votre propre Response
. Elle prend 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()
. Elle vous permet de stocker des réponses non CORS ou d'autres réponses dont le code d'état ne se situe pas 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'objet Response
accepte de nombreux types de données, y compris des Blob
, des ArrayBuffer
, des objets FormData
et des 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 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. Chacun renvoie un Promise
qui se résout avec une valeur d'un autre type.
Méthode | Description |
---|---|
arrayBuffer |
Renvoie un ArrayBuffer contenant le corps, sérialisé en octets.
|
blob |
Renvoie un objet Blob . Si le Response a été créé avec un Blob , ce nouveau Blob aura le même type. Sinon, le Content-Type de l'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 en UTF-8, puis tente de l'analyser en tant que JSON. Renvoie l'objet obtenu ou génère une exception TypeError si la chaîne ne peut pas être analysée en tant que fichier JSON.
|
formData |
Interpréte les octets du corps en tant que formulaire HTML, encodé en tant que multipart/form-data ou 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 à partir d'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 la 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 utilise plus que l'URL. Deux requêtes sont considérées comme différentes si elles ont des chaînes de requête, des en-têtes Vary
ou des méthodes HTTP (GET
, POST
, PUT
, etc.) différents.
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.`);
Pour plus de commodité, vous pouvez rechercher dans tous les caches en même temps à l'aide de 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 les entrées correspondant à un objet Response
. Toutefois, vous pouvez implémenter votre propre recherche à l'aide du filtrage ou en créant un indice.
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;
}
Vous pouvez ainsi 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 méthode d'implémenter votre propre recherche consiste à gérer un index distinct des entrées pouvant être recherchées et à stocker l'index dans IndexedDB. Étant donné qu'il s'agit du type d'opération pour lequel IndexedDB a été conçu, il offre de bien meilleures performances avec un grand nombre d'entrées.
Si vous stockez l'URL de l'Request
avec les propriétés pouvant être recherchées, vous pouvez facilement récupérer la bonne entrée de cache après avoir effectué la recherche.
Supprimer un élément
Pour supprimer un élément d'un cache :
cache.delete(request);
La requête peut être une chaîne Request
ou une 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, qui a été publiée pour la première fois sur WebFundamentals.