DEV Community

Trishul for Itsopensource

Posted on • Edited on • Originally published at itsopensource.com

Offline caching with serviceworkers

Caching always has proven to be the winner when it comes to performance.
Browser by default caches the resources on its end, but to get these resources it still needs the internet. A browser can serve resources from its cache only when a network request is made

Service workers provide a way to bypass the network request. It sits between the network and browser and can decide where to serve resources from.

The basic lifecycle of the service worker is as follows:
Service worker lifecycle


Setup

Register Service worker:

We need to check if the browser supports service workers and then register by providing the path to the serviceworker file.

In Page
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js');
}
Enter fullscreen mode Exit fullscreen mode

Install Service worker:

When the serviceworker is installed (initiated by the script from website), we need to define the resources which we wish to cache, These are cached and linked to specific Cache key.

Ideally, we should not cache any third-party resource but only of which are served from the same domain.

In Service worker
self.addEventListener('install', function (event) {
    event.waitUntil(
        caches.open('cache-key').then(function (cache) {
            return cache.addAll(
                [
                    '/css/style.css',
                    '/js/script.js',
                    '/index.html'
                ]
            );
        })
    );
});
Enter fullscreen mode Exit fullscreen mode

Activate Service worker:

In this step we can delete all the unused cache and also bump the cache version (using cache-key).

In Service worker
self.addEventListener('activate', function (event) {
    event.waitUntil(
        caches.keys().then(function (cacheName) {
            return Promise.all(
                cacheName.filter(function (name) {
                    return name !== 'cache-key';
                }).map(function (name) {
                    return caches.delete(name);
                })
            )
        })
    )
});
Enter fullscreen mode Exit fullscreen mode

Handle network request:

Listen to the fetch event and capture the network request, depending on your cache strategy handle and return the response.

In Service worker
self.addEventListener('fetch', function (event) {
    event.respondWith(
        caches.match(event.request).then(function (response) {
            if (!response) response = fetch(event.request);
            return response;
        })
    );
});
Enter fullscreen mode Exit fullscreen mode

Caching techniques

  • Cache only - This serves the files only and only from the cache, it will never make a network request. Use this if you don't want to update your resource frequently
In Service worker
self.addEventListener('fetch', function(event) {
  event.respondWith(caches.match(event.request));
});
Enter fullscreen mode Exit fullscreen mode
  • Cache, fallback Network - This serves the files from the cache if the file fails to load from the cache it will make a network request.
In Service worker
self.addEventListener('fetch', function (event) {
    event.respondWith(
        caches.match(event.request).then(function (response) {
            if (!response) response = fetch(event.request);
            return response;
        })
    );
});
Enter fullscreen mode Exit fullscreen mode
  • Network, fallback Cache - This makes first a network request and if network request fails then it fallbacks to cache response, please note the cache will be returned only when the network request is completed and gives a failed response.
In Service worker
self.addEventListener('fetch', function (event) {
    event.respondWith(
        fetch(event.request).catch(function () {
            return caches.match(event.request);
        })
    );
});
Enter fullscreen mode Exit fullscreen mode
  • Cache then network - The response is first served from the cache on the page, and then network request is made. When the response from network request is received then again the response is served and the page is updated (or whatever the logic required to do).
In Page
caches.match('/data.json')
    .then(response => {
        updatePage(response);
        fetch('/data.json').
            then(result => {
                updatePage(result);
            })
    })
    .catch(() => {
        fetch('/data.json').
            then(response => {
                updatePage(response);
            })
    });
Enter fullscreen mode Exit fullscreen mode
In Service worker
self.addEventListener('fetch', function (event) {
    event.respondWith(
        caches.open('cache-key').then(function (cache) {
            return fetch(event.request).then(function (response) {
                cache.put(event.request, response.clone());
                return response;
            });
        })
    );
});
Enter fullscreen mode Exit fullscreen mode
  • Serving custom response - This can be the best way to notify the user for an offline connection or some other custom pages.
In Service worker
self.addEventListener('fetch', function (event) {
    event.respondWith(
        // Try the cache
        caches.match(event.request).then(function (response) {
            if (response) {
                return response;
            }
            return fetch(event.request).then(function (response) {
                if (response.status === 404) {
                    return caches.match('/404.html');
                }
                return response
            });
        }).catch(function () {
            return caches.match('/offline.html');
        })
    );
});
Enter fullscreen mode Exit fullscreen mode

While most of the time serviceworkers are constrained to progressive web apps, but these are also used to make websites more performant and better user experience.

Top comments (0)