API Cache: guide rapide

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 au cours de l'exécution de votre application, ou de données 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, quelles que soient la vitesse ou la disponibilité du réseau. Cependant, l'API peut également être utilisée comme 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 détection de caractéristiques simple:

const cacheAvailable = 'caches' in self;

Navigateurs pris en charge

  • 40
  • 16
  • 41
  • 11.1

Source

L'API Cache est accessible depuis une fenêtre, un iFrame, un worker ou un service worker.

Éléments pouvant être stockés

Les caches ne stockent que des paires d'objets Request et Response, qui représentent respectivement les requêtes et les réponses HTTP. Toutefois, les requêtes et les réponses peuvent contenir tout type de données pouvant être transférées via HTTP.

Combien peut-on stocker ?

En bref, beaucoup : au moins quelques centaines de mégaoctets, et potentiellement des centaines de gigaoctets ou plus. Les implémentations des navigateurs varient, mais l'espace de stockage disponible dépend généralement de l'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 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(). Il utilise un paramètre, Request ou URL (string). Il 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 le Promise refuse. 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 correspondant à 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

Vient ensuite cache.addAll(). Son fonctionnement est semblable à celui de add(), mais accepte un tableau d'objets ou d'URL Request (string). Le fonctionnement de cette méthode est semblable à celui de l'appel de cache.add pour chaque requête individuelle, si ce n'est que Promise est rejeté si l'une des requêtes 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 existante correspondante. Les règles de mise en correspondance sont les mêmes que celles décrites dans la section sur la retrieving.

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 vos propres Response. Elle comporte 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 n'est pas compris dans la plage 200. Elle é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 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 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, cette nouvelle Blob a le même type. Sinon, le Content-Type de Response est utilisé.
text Interprète les octets du corps comme une chaîne encodée au format UTF-8.
json Interprète les octets du corps comme une 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 erreur TypeError si la chaîne ne peut pas être analysée en tant que JSON.
formData Interprète les octets du corps au format HTML, encodé au format 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 des données à 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 n'utilise pas seulement l'URL. Deux requêtes sont considérées comme différentes si elles présentent 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 d'options comme 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 sur 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 faire correspondre les entrées à un objet Response. Cependant, vous pouvez implémenter votre propre recherche à l'aide de filtres ou en créant un index.

Filtrage

Pour implémenter votre propre recherche, vous pouvez itérer toutes les entrées et filtrer les résultats pour n'afficher que celles qui vous intéressent. Supposons que vous souhaitiez rechercher 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 cette opération 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 à gérer un index distinct des entrées pouvant faire l'objet d'une recherche et à stocker cet index dans IndexedDB. Dans la mesure où il s'agit du type d'opération pour lequel IndexedDB a été conçu, les performances sont nettement meilleures avec un grand nombre d'entrées.

Si vous stockez l'URL de Request à côté des propriétés de recherche, 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 du cache:

cache.delete(request);

Où la requête peut être un 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});

Suppression d'un cache

Pour supprimer un cache, appelez caches.delete(name). Cette fonction renvoie un Promise qui renvoie true si le cache existait et a été supprimé, ou false dans le cas contraire.

Merci

Merci à Mat Scales qui a écrit la version originale de cet article, publiée pour la première fois sur WebFundamentals.