Service worker - network first then cache with fallback to static page
Asked Answered
D

1

12

I want to add service worker to my site to offer a good offline experience to my site users. (Site back-end is PHP)

I'm still new to Javascript promises and service workers, but here is what i reached so far :

my index.php page has this script to register service worker

<script> 
    if ('serviceWorker' in navigator) { navigator.serviceWorker.register('sw.js')};
</script>

and for service worker file i use the following code

var CACHE_STATIC_NAME = 'static-v74';
var CACHE_DYNAMIC_NAME = 'dynamic-v74';

self.addEventListener('install', function (event) {
  console.log('Installing Service Worker ...', event);
  event.waitUntil(
    caches.open(CACHE_STATIC_NAME)
      .then(function (cache) {
        console.log('Precaching App Shell');
        cache.addAll([
          'offline.php', // offline page
          'assets/bundle.css',
          'assets/bundle.js',
          'assets/images/logo.jpg',
          'assets/images/favicon.ico'
        ]);
      })
  )
});

self.addEventListener('activate', function (event) {
  console.log('Activating Service Worker ....', event);
  event.waitUntil(
    caches.keys()
      .then(function (keyList) {
        return Promise.all(keyList.map(function (key) {
          if (key !== CACHE_STATIC_NAME && key !== CACHE_DYNAMIC_NAME) {
            console.log('Removing old cache.', key);
            return caches.delete(key);
          }
        }));
      })
  );
  return self.clients.claim();
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    // Try the network
    fetch(event.request)
      .then(function(res) {
        return caches.open(CACHE_DYNAMIC_NAME)
          .then(function(cache) {
            // Put in cache if succeeds
            cache.put(event.request.url, res.clone());
            return res;
          })
      })
      .catch(function(err) {
          // Fallback to cache
          return caches.match(event.request);
      })
  );
});

in fact this code is working fine as expected :

(1) It registers the service worker & take copy of my static cache files. (2) When activating a new service worker it removes the old cache. (3) With every new request it fetches from network first & if succeeded it puts a fresh copy of request in cache. (4) If failed to make network request when offline it gives back the user a fresh copy of last network request.

what i want to achieve her is (in case - user is offline - and try to request a new page that isn't in cache, he should be redirected to the (offline.php) page which was saved in the static cache) like the following

// If both (network & cache) fail, show a generic fallback:
return caches.match('offline.php');

but i have a problem that i don't know where exactly should i add this line in my (sw.js) file within (fetch) step, i really tried reading more about service workers & Javascript promises and tried adding this line several times different place in my code, but every time neither make it work but misses up with the previous scenario or keep the scenario but fail to achieve this goal.

Really appreciate your kind help & many thanks in advance.

Detradetract answered 28/4, 2018 at 9:30 Comment(1)
also see caching-strategies, offline-cookbook, and caching-strategies-overviewSteve
N
17

In your fetch event listener:

.catch(function(err) {
      // Fallback to cache
      return caches.match(event.request);
  })

caches.match(event.request) in fact returns a Promise that resolves to undefined if no match is found from the cache.

Check for undefined and return offline.php from cache:

return caches.match(event.request)
  .then(function(res){
    if (res === undefined) { 
      // get and return the offline page
    } 
    return res;
})
Nevus answered 28/4, 2018 at 10:29 Comment(1)
thanks, your code res === undefined is save my dayArteriosclerosis

© 2022 - 2024 — McMap. All rights reserved.