Using the Cache API

作者:Mat Scales

The Cache API is a system for storing and retrieving network requests and corresponding responses. These might be regular requests and responses created in the course of running your application, or they could be created solely for the purpose of storing some data in the cache.

The Cache API was created to enable Service Workers to cache network requests so that they can provide appropriate responses even while offline. However, the API can also be used as a general storage mechanism.

Where is it available?

The API is currently available in Chrome, Opera and Firefox. Both Edge and Safari have marked the API as 'In Development'.

The API is exposed via the globalcachesproperty, so you can test for the presence of the API with a simple feature detection:

const cacheAvailable = 'caches' in self;

The API can be accessed from a window, iframe, worker, or service worker.

What can be stored

The caches only store pairs ofRequestandResponseobjects, representing HTTP requests and responses, respectively. However, the requests and responses can contain any kind of data that can be transferred over HTTP.

Create theRequestobject using a URL for the thing being stored:

const request = new Request('/images/sample1.jpg');

TheResponseobject constructor accepts many types of data, includingBlobs,ArrayBuffers,FormDataobjects, and strings.

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

const stringResponse = new Response('Hello world');

You can set the MIME type of aResponseby setting the appropriate header.

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

Working with Response objects

If you have retrieved aResponseand wish to access it's body, there are several helper methods you can use. Each returns aPromisethat resolves with a value of a different type.

Method Description
arrayBuffer Returns anArrayBuffercontaining the body, serialized to bytes.
blob Returns aBlob. If theResponsewas created with aBlobthen this newBlobhas the same type. Otherwise, theContent-Typeof theResponseis used.
text Interprets the bytes of the body as a UTF-8 encoded string.
json Interprets the bytes of the body as a UTF-8 encoded string, then tries to parse it as JSON. Returns the resulting object, or throws aTypeErrorif the string cannot be parsed as JSON.
formData Interprets the bytes of the body as an HTML form, encoded either as "multipart/form-data" or "application/x-www-form-urlencoded". Returns aFormDataobject, or throws aTypeErrorif the data cannot be parsed.
body Returns aReadableStreamfor the body data.

For example

const response = new Response('Hello world');
response.arrayBuffer().then((buffer) => {
  console.log(new Uint8Array(buffer));
  // Uint8Array(11) [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
});

Creating and opening a cache

To open a cache, use thecaches.open(name)method, passing the name of the cache as the single parameter. If the named cache does not exist it is created. This method returns aPromisethat resolves with theCacheobject.

caches.open('my-cache').then((cache) => {
  // do something with cache...
});

Retrieving from a cache

To find an item in a cache, you can use thematchmethod.

cache.match(request).then((response) => console.log(request, response));

Ifrequestis a string it is first be converted to aRequestby callingnew Request(request). The function returns aPromisethat resolves to aResponseif a matching entry is found, orundefinedotherwise.

To determine if twoRequestsmatch, more than just the URL is used. Two requests are considered different if they have different query strings,Varyheaders and/or methods (GET,POST,PUT, etc.).

You can ignore some or all of these things by passing an options object as a second parameter.

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

cache.match(request, options).then(...);

If more than one cached request matches then the one that was created first is returned.

If you want to retrieve_all_matching responses, you can usecache.matchAll.

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

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

As a shortcut you can search over all caches at once by usingcaches.match()instead of callingcache.match()for each cache.

Searching

The Cache API does not provide a way to search for requests or responses except for matching entries against aResponseobject. However, you can implement your own search using filtering or by creating an index.

Filtering

One way to implement your own search is to iterate over all entries and filter down to the ones that you want. Let's say that you want to find all items that have URLs ending with '.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;
}

This way you can use any property of theRequestandResponseobjects to filter the entries. Note that this is slow if you search over large sets of data.

Creating an index

The other way to implement your own search is to maintain a separate index of entries that can be searched, stored in IndexedDB. Since this is the kind of operation that IndexedDB was designed for it has much better performance with large numbers of entries.

If you store the URL of theRequestalongside the searchable properties then you can easily retrieve the correct cache entry after doing the search.

Adding to a cache

There are three ways to add an item to a cache -put,addandaddAll. All three methods return aPromise.

cache.put

The first is to usecache.put(request, response).requestis either aRequestobject or a string - if it is a string, thennew Request(request)is used instead.responsemust be aResponse. This pair is stored in the cache.

cache.put('/test.json', new Response('{"foo": "bar"}'));

cache.add

The second is to usecache.add(request).requestis treated the same as forput, but theResponsethat is stored in the cache is the result of fetching the request from the network. If the fetch fails, or if the status code of the response is not in the 200 range, then nothing is stored and thePromiserejects. Note that cross-origin requests not in CORS mode have a status of 0, and therefore such requests can only be stored withput.

cache.addAll

Thirdly, there iscache.addAll(requests), whererequestsis an array ofRequests or URL strings. This works similarly to callingcache.addfor each individual request, except that thePromiserejects if any single request is not cached.

In each of these cases, a new entry overwrites any matching existing entry. This uses the same matching rules described in the section on retrieving.

Deleting an item

To delete an item from a cache:

cache.delete(request);

Where request can be aRequestor a URL string. This method also takes the same options object ascache.match, which allows you to delete multipleRequest/Responsepairs for the same URL.

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

Deleting a cache

To delete a cache, callcaches.delete(name). This function returns aPromisethat resolves totrueif the cache existed and was deleted, orfalseotherwise.

results matching ""

    No results matching ""