Service workers and the Cache Storage API
You're locked in a struggle for network reliability. The browser's HTTP cache is your first line of defense, but as you've learned, it's only really effective when loading versioned URLs that you've previously visited. On its own, the HTTP cache is not enough.
Fortunately, two newer tools are available to help turn the tide in your favor: service workers and the Cache Storage API. Since they're so often used together, it's worth learning about them both at the same time.
Service workers #
A service worker has some special powers. Among other duties, it patiently waits for your web app to make an outgoing request, and then springs into action by intercepting it. What the service worker does with this intercepted request is up to you.
For some requests, the best course of action might be just to allow the request to continue on to the network, just like what would happen if there were no service worker at all.
For other requests, though, you can take advantage of something more flexible than the browser's HTTP cache, and return a reliably fast response without having to worry about the network. That entails using the other piece of the puzzle: the Cache Storage API.
The Cache Storage API #
- Chrome 43, Supported 43
- Firefox 41, Supported 41
- Edge 16, Supported 16
- Safari 11.1, Supported 11.1
Wait… there's another cache to think about now? #
You're probably asking yourself questions like "Do I still need to configure my HTTP headers?" and "What can I do with this new cache that wasn't possible with the HTTP cache?" Don't worry—those are natural reactions.
It's still recommended that you configure the
Cache-Control headers on your web server, even when you know that you're using the Cache Storage API. You can usually get away with setting
Cache-Control: no-cache for unversioned URLs, and/or
Cache-Control: max-age=31536000 for URLs that contain versioning information, like hashes.
When populating the Cache Storage API cache, the browser defaults to checking for existing entries in the HTTP cache, and uses those if found. If you're adding versioned URLs to the Cache Storage API cache, the browser avoids an additional network request. The flip side of this is that if you're using misconfigured
Cache-Control headers, like specifying a long-lived cache lifetime for an unversioned URL, you can end up making things worse by adding that stale content to the Cache Storage API. Getting your HTTP cache behavior sorted is a prerequisite for effectively using the Cache Storage API.
As for what's now possible with this new API, the answer is: a lot. Some common uses that would be difficult or impossible with just the HTTP cache include:
- Use a "refresh in the background" approach to cached content, known as stale-while-revalidate.
- Impose a cap on the maximum number of assets to cache, and implement a custom expiration policy to remove items once that limit is reached.
- Compare previously cached and fresh network responses to see if anything's changed, and enable the user to update content (with a button, for example) when data has actually been updated.
Check out The Cache API: A quick guide to learn more.
API nuts and bolts #
There are some things to keep in mind about the API's design:
Requestobjects are used as the unique keys when reading and writing to these caches. As a convenience, you can pass in a URL string like
'https://example.com/index.html'as the key instead of an actual
Requestobject, and the API will automatically handle that for you.
Responseobjects are used as the values in these caches.
Cache-Controlheader on a given
Responseis effectively ignored when caching data. There are no automatic, built-in expiration or freshness checks, and once you store an item in the cache, it will persist until your code explicitly removes it. (There are libraries to simplify cache maintenance on your behalf. They'll be covered later on in this series.)
- Unlike with older, synchronous APIs such as
LocalStorage, all Cache Storage API operations are asynchronous.
A quick detour: promises and async/await #
Service workers and the Cache Storage API use asynchronous programming concepts. In particular, they rely heavily on promises to represent the future result of async operations. You should familiarize yourself with promises, and the related
await syntax, before diving in.
Don't deploy that code… yet #
While they provide an important foundation, and can be used as-is, both service workers and the Cache Storage API are effectively lower-level building blocks, with a number of edge cases and "gotchas". There are some higher-level tools that can help smooth the difficult bits of those APIs, and provide all you need to build a production-ready service worker. The next guide covers one such tool: Workbox.