Many have heard of Service Workers but few have heard of CacheStorage. If you are one of them, don’t worry this post will serve as both a guide and tutor on the basics of CacheStorage. If you have heard of CacheStorage this post will broaden your knowledge. OK, let’s dive in!

In this post we will look into the CacheStorage API, I will take each API on the CacheStorage and Cache interfaces and explain with examples how they work and how to use them.

Note: CacheStorage and Service Workers are not tied together. They are two different concepts. We will look at them in the below sections.

Tip: When building web apps use Bit to reuse components! Easily share and sync them across your app to build faster with your team. Give it a try.

React spinners with Bit: choose, play, install

What is CacheStorage?

Introduction to a Progressive Web Application API called Cache Storage, which is where Service Workers can download and store a complete version of an application — Angular University

CacheStorage is a storage mechanism in browsers for storing and retrieving network requests and response. It stores a pair of Request and Response objects. The Request as the key and Response as the value.

The Request object is used to send an HTTP request over a network, the network responds with a Response object from the server. Now, the two forms a pair, much like a question and an answer.

Let’s say we request for an image from a server:

// question: Please, server I need an image `image.png`

const req = new Request('/image.jpg)

We will get the response like this:

// Server: Hello Request, see the image you requested. Much please doing buisness with you

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

// here, res contains the image data

req and res will be stored in the Cache like this:

Cache

-------------

key | value

-------------

req | res

So to get res Response object we will reference it from req which is it’s key.

log(Cache[req])

It will return req.

If we request for a particular page:

const req1 = new Request('/index.html')

The response will be like this:

const res1 = new Response(body);

Now, the Cache will be updated:

Cache

-------------

key | value

-------------

req | res

req1 | res1

CacheStorage and Service Workers

CacheStorage is not a Service Worker API, but it enables SW to cache network responses so that they can provide offline capabilities when the user is disconnected from the network. You can use other storage mechanisms in SW. For example, IndexedDB, a SQL database in the browser, can be used to store network responses.

CacheStorage can be used in the DOM thread not only in the Worker thread:

<script>

if('caches' in window) {

caches.open('cache_name').then((cache) => {

// ...

}).catch((err) => {

// ...

})

}

</script>

Though The CacheStorage was created to enable SW store network requests and responses as we said earlier it can also be used in the DOM(window, iframe) as a storage utility.

For example, we can store a user’s password, key or an application state and retrieve them whenever we want.

caches Object

The caches (an instance of CacheStorage) object is used to access the CacheStorage, to retrieve, store and delete objects.

The caches object is global, it is located in the window object.

To detect whether your browser supports CacheStorage, run the below code:

<script>

if ('caches' in window) {

caches.open('cache_name').then((cache) => {

// ...

}).catch((err) => {

// ...

})

}

</script>

The caches object stores and maintains a list of Caches created. In order to manage this Caches, the caches object has many methods to help it carry out its maintenance work. We will look at the methods below.

CacheStorage API Methods — Creating a Cache

We can create a Cache by calling the open(…) method. The open method takes a string which bears the name of the cache to open.

When the open method is called with the cache name, it searches for the cache name in its list of Caches and returns the Cache with reference to the cache name. If the Cache is not found, the open method creates the Cache and returns a handle to it.

<script>

const l = console.log

if ('caches' in window) {

caches.open('cache_name').then((cache) => {

l(cache)

}).catch((err) => {

l(err)

})

}

</script>

Note: CacheStorage API is Promise-based. They return PRomise, so you have to resolve and reject them to get their status.

In the above, we tried opening the cache_name Cache by calling the open method in the caches object with the cache name as the parameter. The method returns a Promise, it resolves if the Cache is successfully created or rejects if the operation failed.

We used the then method to get the resolved value. The resolved value is a handle to the Cache.

CacheStorage API Methods — Checking a Cache

We can check if a Cache object exists by calling the has() method with the name of the cache object.

<script>

const l = console.log

if ('caches' in window) {

caches.has('cache_name').then((bool) => {

l(bool)

}).catch((err) => { })

}

</script>

It returns a Promise and a boolean value bool , the bool is true if the Cache was found or false if the Cache wasn't found.

For example:

<script>

const l = console.log if ('caches' in window) { caches.open('cache_name').then((cache) => {

alert(cache.add)

}).catch((err) => {

l(err)

}) caches.has('cache_name').then((bool) => {

l(bool) // true

}).catch((err) => { }) caches.has('cache_name_1').then((bool) => {

l(bool) // false

}).catch((err) => {

l(err)

}) }

</script>

We added to the code in our previous section. We created the cache-name cache, then called has() method passing in the cache name cache-name . Being previously created this will log true . Next, we called the has method passing in cache_name_1 , this will log false because we didn't create a cache_name_1 cache.

CacheStorage API Methods — Delete a Cache

We can delete an already existing Cache by using the delete method. We create a cache like this:

<script>

const l = console.log if ('caches' in window) {

caches.open('cache_name').then((cache) => {

alert(cache.add)

}).catch((err) => {

l(err)

})

}

</script>

We can delete the cache-name Cache by calling the delete() method and passing the name of the cache cache-name :

<script>

const l = console.log if ('caches' in window) { caches.open('cache_name').then((cache) => {

l(cache)

}).catch((err) => {

l(err)

}) caches.delete('cache_name').then((bool) => {

l(bool) // true

}).catch((err) => { }) }

</script>

It returns a Promise that resolves with a boolean. If the boolean is true that means the Cache was successfully deleted. If it succeeds we will have true logged in our console.

If we call the has method after the delete call, it will surely log false because it won’t find the Cache because it has been deleted by the delete call.

<script>

const l = console.log if ('caches' in window) {

caches.open('cache_name').then((cache) => {

l(cache.add)

}).catch((err) => {

l(err)

}) caches.delete('cache_name').then((bool) => {

l(bool)

}) caches.has('cache_name').then((bool) => {

l(bool) // surely logs false if `delete(...)` succeeds.

}).catch((err) => { })

}

</script>

CacheStorage API Methods — Listing the Cache objects

To view Cache objects that have been created we use the keys method to list all the Cache objects in our storage.

<script>

const l = console.log if ('caches' in window) {

caches.open('cache_name').then((cache) => {

l(cache)

}).catch((err) => {

l(err)

})

caches.open('cache_name-1').then((cache) => {

l(cache)

}).catch((err) => {

l(err)

})

caches.open('cache_name-2').then((cache) => {

l(cache)

}).catch((err) => {

l(err)

}) caches.keys().then(function(caches) {

l(caches);

});

}

</script>

It returns a Promise that resolves to an array of Cache objects.

CacheStorage API Methods — Retrieve a Cache object from the pool

We can retrieve a Cache object by calling the match method passing in the Cache name.

This method returns a Promise which resolves to a Response or undefined if the Cache is not found.

<script>

const l = console.log



if ('caches' in window) {

caches.open('cache_name').then((cache) => {

l(cache)

}).catch((err) => {

l(err)

})

caches.match('cache_name').then((cache)=>{

l(cache)

})

}

</script>

In the next section, we will explore the Cache API methods.

Cache API Methods

Cache is what the CacheStorage returns when it finishes the creation of a Cache through CacheStorage.open() . With this access to the Cache, we can store resources inside the instance. Once we have access to a Cache object we can store, delete or retrieve a Response object from the Cache.

The first method we will look at is:

Cache API Method — Adding to a Cache

One of the essential operations we will carry out is storing a pair of Request and Response to a Cache. We use the following methods to carry the operation: add, addAll and put. They all return a Promise and attaches a callback for only the rejection of the Promise.

add This takes a Request object or a URL string and fetches the data over a network, the response from the network request is cached with the URL string or Request object as the key.

<script>

const l = console.log if ('caches' in window) {

caches.open('cache_name').then((cache) => {

cache.add('/')

}).catch((err) => {

l(err)

})

}

</script>

Here we requested for the main page of our app to be cached. Cache will perform a fetch against the passed / URL and cache the Response with the / URL being the key.

Open your DevTools and click on Application. Click on the CacheStorage tab and click on the cache_name . You will see the right-hand side empty.

OK, move to the Network tab, you will see only our page in the Network tab as the only page fetched. Now, load the page above to run the code.

You will see an entry appear in the Network tab. You will see it log / , that's the URL string it fetched from the network when the cache.open('/') was run. This verifies our claim that the add method performs a network request to fetch the resource of the URL/Request object passed to it.

Now, move to Application > CacheStorage > cache_name and click on the refresh icon. You will see http://127.0.0.1:8080/ appear on the right side.

This shows the URL and the Response was stored in the Cache.

addAll This is similar to add except here it takes URL strings or Request objects in an array and performs add() on each of them. If fetch on one of the URL strings or Request objects in the array fails, the whole addAll operation comes down(terminates).

<script>

const l = console.log if ('caches' in window) {

caches.open('cache_name').then((cache) => {

l(cache)

cache.addAll(['/','/faq','/contact','/about'])

}).catch((err) => {

l(err)

})

}

</scrip>

The above code will attempt to fetch and cache the main page / , the FAQ page /faq , the contact page /contact and the about page /about . If one fails to fetch its resource maybe due to network failure or resource not found, none of the other resources would be cached even if they were successful.

put This takes a different route altogether. It allows us to specify both the URL string or Request object and the Response object.

<script>

const l = console.log if ('caches' in window) {

fetch('/faq').then(function(response) {

return caches.open('cache_name').then(function(cache) {

return cache.put('/faq', response)

})

})

}

</script>

In the above code, we fetch the FAQ page /faq resource using the fetch() function, next we resolve to open the cache_name cache and add the /faq URL string as the key to the response object using the put() method.

Cache API Method — Deleting from a Cache

We can remove a cached request from a Cache, this done through the use of the delete method.

<script>

const l = console.log if ('caches' in window) {

caches.open('cache_name').then((cache) => {

cache.add('/') cache.delete('/') }).catch((err) => {

l(err)

})

}

</script>

In the above code, we create a / entry via add() and we delete by calling delete() and passing in / string.

Looking at the DevTools > Appliaction > CacheStorage > cache_name, we will see that / will be gone.

Cache API Method — Getting all your keys

To return all the keys created in our cache, we call the keys() method. This keys() method returns a Promise that resolves to an array of Cache keys.

<script>

const l = console.log if ('caches' in window) {

caches.open('cache_name').then((cache) => {

cache.addAll(['/', '/faq', '/contact'])

cache.keys().then(function(keys) {

l(keys); // Array [Request, Request, Request]

});

}).catch((err) => {

l(err)

})

}

</script>

The method returns a Promise that resolves to an array of Cache request keys.

Cache API Method — match/matchAll

match We can find an item in a cache by using the cache.match(…)

<script>

const l = console.log if ('caches' in window) {

caches.open('cache_name').then((cache) => {

cache.addAll(['/', '/faq', '/contact'])

cache.match('faq').then((response)=> {

l(response)

})

}).catch((err) => {

l(err)

})

}

</script>

In the above code, we cached / , /faq and /contact requests. Next, we tried retrieving the /faq response from the cache. If a string is passed to match(...) it will be converted to a Request object and its corresponding Response is retrieved from the cache.

matchAll There are cases whereby the match will return many hits, cache.match(…) will only return the first hit in the cache. To return many results we will use cache.matchAll(…):

<script>

const l = console.log if ('caches' in window) {

caches.open('cache_name').then((cache) => {

cache.addAll(['/', '/faq', '/contact'])

cache.matchAll('faq').then((response)=> {

l(`Results: ${response}`)

})

}).catch((err) => {

l(err)

})

}

</script>

Conclusion

In the post, we covered a lot on CacheStorage. We started from learning what CacheStorage does to its relationship with Service workers and finally, we took each API apart, explaining with examples how they work and how to use them.

We saw the power of CacheStorage, it is up to you to know when to use it to your benefit.

If you have any question regarding this or anything I should add, correct or remove, feel free to comment, email or DM me

Thanks !!!