Working With The JavaScript Cache API
Working With The JavaScript Cache API
Working With The JavaScript Cache API
blog.logrocket.com/javascript-cache-api
Introduction
The Cache API provides a mechanism for storing network requests and retrieving their
corresponding responses during run-time. It can be used in the absence of an internet
connection (or presence of a flaky one) and this makes it integral to the building of
progressive web applications (fully optimised web applications that work offline like
native applications).
Progressive web applications were created to ensure that web services work on all
devices. On mobile devices, they are designed to deliver a user experience that is close to
that of native applications. Under the hood, PWAs use service workers to achieve the
ideal behavior, and they leverage the Cache API for extra control over network
resources.
This Google web fundamentals page describes service workers like this:
1/7
A service worker is a script that your browser runs in the background, separate from a
web page, opening the door to features that don’t need a web page or user interaction.
Today, they already include features like push notifications and background sync. In the
future, service workers might support other things like periodic sync or geofencing. A
core feature of a service worker is the ability to intercept and handle network requests,
including programmatically managing a cache of responses.
We can see that caching can play an important role in the workflow of service workers.
This article shows how the Cache API can be used in a service worker, and as a general
mechanism of resource storage.
All the code in this tutorial can be found in this repository, feel free to fork it or send in
a PR.
Pro tip: In Chrome, you can visit chrome://inspect/#service-workers and click on the
“inspect” option (directly under the origin of any already opened tab) to view logging
statements for the actions of the service-worker.js script.
Edge >= 17
Opera >= 27
Safari >= 11.1
Firefox >= 39
Chrome >= 40
iOS Safari = 11.4 >
UC Browser 11.8 >=
Chrome for Android >= 67
Because older browsers may not support the API, it is good practice to check for its
availability before attempting to reference it. The caches property is available on the
window object and we can check that it is implemented in the browser with this
snippet:
if ('caches' in window){
Usage
2/7
The Cache API is a great choice for caching URL-addressable resources, that is, you
should use the Cache API when you work with network resources that are necessary to
load your application. If your application deals with lots of data, you may cache the data
that the user will most likely need on page load. These resources may include file-based
content, assets, API responses, and web pages.
For the storage of significant amounts of structured data (including files/blobs), you
should ideally use the IndexedDB API.
The Cache API ships with several methods to perform the following (CRUD) operations:
The snippet above receives the name of the cache as the single parameter and goes on to
create the cache with that name. The caches.open() method first checks if a cache with
that name already exists. If it doesn’t, it creates it and returns a Promise that resolves
with the Cache object.
After the snippet executes, we will now have a new cache object that can be referenced
with the name new-cache.
1. add
2. addAll
3. put
All of these methods return a Promise , now let’s go over each of these and see how
they differ from one another.
Cache.add()
3/7
The first method, cache.add() , takes a single parameter that can either be a URL string
literal or a Request object. A call to the cache.add() method will make a Fetch request
to the network and store the response in the associated cache object:
newCache.add('/cats.json')
const options = {
method: "GET",
headers: new Headers({
'Content-Type': 'text/html'
}),
}
newCache.add(new Request('/cats.json', options))
Note: If the fetch is unsuccessful and an error response is returned, nothing is stored in
the cache and the
Promise rejects.
Cache.addAll()
This method works similarly to the cache.add() method except that it takes in an array
of request URL string literals or Request objects and returns a promise when all the
resources have been cached:
Note: The promise rejects if one or more items in the array of requests are not cached.
Also, while the items in the array are being cached, a new entry overwrites any matching
existing entry.
Cache.put()
The Cache.put method works quite differently from the rest as it allows an extra layer
of control. The put() method takes two parameters, the first can either be a URL string
literal or a Request object, the second is a Response either from the network or
generated within your code:
// Create a new entry for cats.json and store the generated response
newCache.put('/cats.json', new Response('{"james": "kitten", "daniel": "kitten"}'))
// Fetch a response from an external address and create a new entry for cats.json
newCache.put('https://pets/cats.json');
4/7
The put method allows an extra layer of control as it lets you store responses that do
not depend on CORS or other responses that are dependent on a server response status
code.
Pro tip: The first two methods — add() and addAll() — are dependent on the state of
CORS on the server the data is being requested from. If a CORS check fails, nothing gets
cached and the Promise rejects. Using put() , on the other hand, gives you extra
confidence as you can set an in-house response.
In the code above, we passed in a request variable to the match method, if the
request variable is a URL string, it is converted to a Request object and used as an
argument. The match method will return a Promise that resolves to a Response
object if a matching entry is found.
The browser uses different factors in determining if two or more Requests match. A
Request may have the same URL as another but use a different HTTP method. Two
such requests are considered to be different by the browser.
When using the match method, we can also pass an options object as the second
parameter. This object has key value pairs that tell match to ignore specific factors
when matching a request:
In a case where more than one cache item matches, the oldest one is returned. If we
intend to retrieve all matching responses, we can use the matchAll() method.
5/7
const request = '/cats.json';
newCache.delete(request);
In the code above, we saved a URL string in the request variable but we can also pass in
a Request object to the delete method. In a case where we have more than one
matching entries, we can pass in a similar options Object as we did with the match
method.
Deleting a cache
Finally, we can delete a cache by calling the delete() method on the caches property of
the window object. Let’s delete our cache in the snippet below:
Note: When a cache is deleted, the delete() method returns a Promise if the cache
was actually deleted and a false if something went wrong or the cache doesn’t exist.
Conclusion
In this article, we took a tour of the Cache API and discussed its usefulness to the
development of progressive web applications. We also explored its CRUD methods and
saw how easily we can retrieve responses and store requests.
Note: For security reasons, a cache is bound to the current origin and other origins cannot
access the caches set up for other origins.
All the code in this tutorial can be found in this repository, feel free to fork it or send in
a PR.
LogRocket allows you to understand these errors in new and unique ways. Our frontend
monitoring solution tracks user engagement with your JavaScript frontends to give you
the ability to find out exactly what the user did that led to an error.
6/7
LogRocket records console logs, page load times, stacktraces, slow network
requests/responses with headers + bodies, browser metadata, and custom logs.
Understanding the impact of your JavaScript code will never be easier!
7/7