In our last post we discussed about adding service workers to your site and converting your web app into a Progressive Web App(PWA). In this post we will discuss some of the pitfalls to avoid and the caching strategies that we can employ with service workers.
Service Worker LifeCycle
When you first register a service worker, they move to the installing state after successful registration. Now if there is no existing active service workers, the installed service worker moves on to the activated state from where it can run its code and respond to requests.
if there is an activated service worker present, the new installed service worker will not be able to activate until all the page where the service worker controls is closed or navigated away from. This means that even if the user reloads your page, the same old service worker will still control the page. To overcome this we can call the skipWaiting() function in the install event of the service worker so that the new service workers will always override the current service workers
self.addEventListener('install', function(event) {
skipWaiting();
});
Cached Service Worker
The service worker script might itself be cached, causing your website to use old resources unless the user manually clears the cache. It is important to set the service worker cache-control header to 0 so that service workers are never cached.
Caching Strategies
A few simple caching strategies are given below.
Cache fallback
In this method, first we cache resources, then in the fetch event, all request are first fetched from the network, if the network fails, then attempt to fetch the resource from the cache if it exists.
self.addEventListener('install', function(event) {
event.waitUntil(function(){
caches.open(cache_name).then(function(cache){
return cache.addAll([
//Array of resources to cache
])
})
})
})
self.addEventListener('fetch', function(event) {
event.respondWith(fetch(event.request).then(function(res){
//return response from network
}, function (e){
//get resource from cache
caches.open(cache_name).then(function(cache){
cache.match(request).then(function(item){
if(item)
//return resource from cache
else
//not found in cache
}, function (e){
//cache error
})
})
})
});
Cache Only
The cache only strategy is useful for static sites which update infrequently, in this technique, we cache all the static resources needed and then all requests are served from the cache only
First we cache all the resources needed
self.addEventListener('install', function(event) {
event.waitUntil(function(){
caches.open(cache_name).then(function(cache){
return cache.addAll([
//Array of resources to cache
])
})
})
})
Next, all fetch request are from the cache only
self.addEventListener('fetch', function(event) {
event.respondWith(caches.open(cache_name).then(function(cache){
cache.match(request).then(function(item){
if(item)
//return resource from cache
else
//not found in cache
}, function (e){
//cache error
})
})
})
});
Cache and Update
This method is similar to the cache only method, the only difference is that we after we fetch a request from the cache we also fetch the request from the network and update the cache.
self.addEventListener('fetch', function(event) {
event.respondWith(
// code to fetch resource from cache
)
event.waitUntil(function(event.request){
caches.open(cache_name).then(function(cache){
fetch(event.request).then(function (res) {
cache.put(event.request, res);
})
})
})
});
*Service Worker Lifecycle Image from https://developers.google.com/web/fundamentals/primers/service-workers/