Progressive Web Apps Caching Strategies

Spread the love

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

sw 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/