Die Cache API: Eine Kurzanleitung

Informationen zum Verwenden der Cache API, um Ihre Anwendungsdaten offline verfügbar zu machen

Die Cache API ist ein System zum Speichern und Abrufen von Netzwerkanfragen und der zugehörigen Antworten. Dies können normale Anfragen und Antworten sein, die beim Ausführen Ihrer Anwendung erstellt wurden, oder sie können ausschließlich zum Speichern von Daten für die spätere Verwendung erstellt werden.

Die Cache API wurde entwickelt, damit Service Worker Netzwerkanfragen im Cache speichern können, um unabhängig von der Netzwerkgeschwindigkeit oder -verfügbarkeit schnelle Antworten zu liefern. Die API kann jedoch auch als allgemeiner Speichermechanismus verwendet werden.

Die Cache API ist in allen modernen Browsern verfügbar. Sie wird über das globale Attribut caches bereitgestellt. So können Sie mit einer einfachen Funktionserkennung prüfen, ob die API verfügbar ist:

const cacheAvailable = 'caches' in self;

Unterstützte Browser

  • Chrome: 40.
  • Edge: 16.
  • Firefox: 41.
  • Safari: 11.1.

Quelle

Der Cache API kann über ein Fenster, einen IFrame, einen Worker oder einen Service Worker zugegriffen werden.

Was kann gespeichert werden?

Die Caches speichern nur Paare von Request- und Response-Objekten, die jeweils HTTP-Anfragen und ‑Antworten darstellen. Die Anfragen und Antworten können jedoch jede Art von Daten enthalten, die über HTTP übertragen werden können.

Wie viel kann gespeichert werden?

Kurz gesagt: Sehr viel, mindestens ein paar hundert Megabyte und potenziell Hunderte von Gigabyte oder mehr. Browserimplementierungen variieren, aber die verfügbare Speichermenge basiert in der Regel auf der Speichermenge, die auf dem Gerät verfügbar ist.

Cache erstellen und öffnen

Verwenden Sie die Methode caches.open(name), um einen Cache zu öffnen, und geben Sie den Namen des Caches als einzigen Parameter an. Wenn der benannte Cache nicht vorhanden ist, wird er erstellt. Diese Methode gibt eine Promise zurück, die mit dem Cache-Objekt aufgelöst wird.

const cache = await caches.open('my-cache');
// do something with cache...

Elemente zu einem Cache hinzufügen

Es gibt drei Möglichkeiten, einem Cache einen Artikel hinzuzufügen: add, addAll und put. Alle drei Methoden geben eine Promise zurück.

cache.add

Zuerst ist da cache.add(). Er nimmt einen Parameter entgegen, entweder einen Request oder eine URL (string). Er sendet eine Anfrage an das Netzwerk und speichert die Antwort im Cache. Wenn der Abruf fehlschlägt oder der Statuscode der Antwort nicht im Bereich 200 liegt, wird nichts gespeichert und der Promise wird abgelehnt. Anfragen zwischen verschiedenen Ursprüngen, die nicht im CORS-Modus sind, können nicht gespeichert werden, da sie einen status von 0 zurückgeben. Solche Anfragen können nur mit put gespeichert werden.

// 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

Als Nächstes kommt cache.addAll(). Sie funktioniert ähnlich wie add(), nimmt aber ein Array von Request-Objekten oder string-URLs an. Das funktioniert ähnlich wie das Aufrufen von cache.add für jede einzelne Anfrage, mit der Ausnahme, dass Promise abgelehnt wird, wenn eine einzelne Anfrage nicht im Cache gespeichert ist.

const urls = ['/weather/today.json', '/weather/tomorrow.json'];
cache.addAll(urls);

In jedem dieser Fälle wird ein übereinstimmender vorhandener Eintrag durch einen neuen Eintrag überschrieben. Dabei werden dieselben Abgleichsregeln verwendet, die im Abschnitt Abrufen beschrieben wurden.

cache.put

Schließlich gibt es cache.put(), mit dem Sie entweder eine Antwort aus dem Netzwerk speichern oder eine eigene Response erstellen und speichern können. Er nimmt zwei Parameter entgegen. Das erste kann entweder ein Request-Objekt oder eine URL (string) sein. Das zweite muss ein Response sein, entweder aus dem Netzwerk oder durch deinen Code generiert.

// 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');

Die Methode put() ist toleranter als add() oder addAll() und ermöglicht das Speichern von Antworten, die nicht CORS-kompatibel sind, oder anderer Antworten, deren Statuscode nicht im Bereich 200 liegt. Dadurch werden alle vorherigen Antworten für dieselbe Anfrage überschrieben.

Anfrageobjekte erstellen

Erstellen Sie das Request-Objekt mit einer URL für das gespeicherte Element:

const request = new Request('/my-data-store/item-id');

Mit Antwortobjekten arbeiten

Der Konstruktor für Response-Objekte akzeptiert viele Datentypen, darunter Blob-, ArrayBuffer-, FormData-Objekte und Strings.

const imageBlob = new Blob([data], {type: 'image/jpeg'});
const imageResponse = new Response(imageBlob);
const stringResponse = new Response('Hello world');

Sie können den MIME-Typ einer Response festlegen, indem Sie den entsprechenden Header festlegen.

  const options = {
    headers: {
      'Content-Type': 'application/json'
    }
  }
  const jsonResponse = new Response('{}', options);

Wenn Sie eine Response abgerufen haben und auf den Textkörper zugreifen möchten, stehen Ihnen mehrere Hilfsmethoden zur Verfügung. Jede Funktion gibt eine Promise zurück, die in einen Wert eines anderen Typs aufgelöst wird.

Methode Beschreibung
arrayBuffer Gibt ein ArrayBuffer mit dem Text zurück, das in Bytes serialisiert ist.
blob Gibt Blob zurück. Wenn die Response mit einer Blob erstellt wurde, hat diese neue Blob denselben Typ. Andernfalls wird die Content-Type der Response verwendet.
text Die Bytes des Body werden als UTF-8-codierter String interpretiert.
json Die Bytes des Textkörpers werden als UTF-8-codierter String interpretiert und dann als JSON geparst. Gibt das resultierende Objekt zurück oder wirft eine TypeError, wenn der String nicht als JSON geparst werden kann.
formData Die Bytes des Textkörpers werden als HTML-Formular interpretiert, das entweder als multipart/form-data oder application/x-www-form-urlencoded codiert ist. Gibt ein FormData-Objekt zurück oder wirft eine TypeError, wenn die Daten nicht geparst werden können.
body Gibt einen ReadableStream für die Textdaten zurück.

Beispiel:

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]

Daten aus einem Cache abrufen

Wenn Sie ein Element in einem Cache suchen möchten, können Sie die Methode match verwenden.

const response = await cache.match(request);
console.log(request, response);

Wenn request ein String ist, wandelt der Browser ihn durch Aufrufen von new Request(request) in einen Request um. Die Funktion gibt eine Promise zurück, die in Response umgewandelt wird, wenn ein übereinstimmender Eintrag gefunden wird, andernfalls in undefined.

Um festzustellen, ob zwei Requests übereinstimmen, verwendet der Browser nicht nur die URL. Zwei Anfragen gelten als unterschiedlich, wenn sie unterschiedliche Suchstrings, Vary-Header oder HTTP-Methoden (GET, POST, PUT usw.) haben.

Sie können einige oder alle diese Elemente ignorieren, indem Sie ein Optionsobjekt als zweiten Parameter übergeben.

const options = {
  ignoreSearch: true,
  ignoreMethod: true,
  ignoreVary: true
};

const response = await cache.match(request, options);
// do something with the response

Wenn mehrere im Cache gespeicherte Anfragen übereinstimmen, wird diejenige zurückgegeben, die zuerst erstellt wurde. Wenn Sie alle übereinstimmenden Antworten abrufen möchten, können Sie cache.matchAll() verwenden.

const options = {
  ignoreSearch: true,
  ignoreMethod: true,
  ignoreVary: true
};

const responses = await cache.matchAll(request, options);
console.log(`There are ${responses.length} matching responses.`);

Als Verknüpfung können Sie alle Caches gleichzeitig durchsuchen, indem Sie caches.match() verwenden, anstatt für jeden Cache cache.match() aufzurufen.

Suchen

Die Cache API bietet keine Möglichkeit, nach Anfragen oder Antworten zu suchen, es sei denn, Einträge werden mit einem Response-Objekt abgeglichen. Sie können jedoch eine eigene Suche mithilfe von Filtern oder durch Erstellen eines Index implementieren.

Filtern

Eine Möglichkeit, eine eigene Suche zu implementieren, besteht darin, alle Einträge zu durchlaufen und die gewünschten herauszufiltern. Angenommen, Sie möchten alle Elemente finden, deren URLs auf .png enden.

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;
}

So können Sie beliebige Properties der Objekte Request und Response verwenden, um die Einträge zu filtern. Beachten Sie, dass dies bei der Suche in großen Datenmengen langsam ist.

Index erstellen

Die andere Möglichkeit, eine eigene Suche zu implementieren, besteht darin, einen separaten Index von Einträgen zu verwalten, der durchsucht werden kann, und den Index in IndexedDB zu speichern. Da IndexedDB für diese Art von Vorgängen entwickelt wurde, ist die Leistung bei einer großen Anzahl von Einträgen viel besser.

Wenn Sie die URL der Request zusammen mit den suchbaren Properties speichern, können Sie nach der Suche ganz einfach den richtigen Cache-Eintrag abrufen.

Elemente löschen

So löschen Sie ein Element aus einem Cache:

cache.delete(request);

Dabei kann „request“ ein Request- oder ein URL-String sein. Bei dieser Methode wird auch dasselbe Optionsobjekt wie bei cache.match verwendet. So können Sie mehrere Request/Response-Paare für dieselbe URL löschen.

cache.delete('/example/file.txt', {ignoreVary: true, ignoreSearch: true});

Cache löschen

Wenn Sie einen Cache löschen möchten, rufen Sie caches.delete(name) auf. Diese Funktion gibt einen Promise zurück, der in true aufgelöst wird, wenn der Cache vorhanden war und gelöscht wurde, andernfalls in false.

Vielen Dank

Vielen Dank an Mat Scales, der die ursprüngliche Version dieses Artikels verfasst hat, die zuerst auf WebFundamentals veröffentlicht wurde.