DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 966,155 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Trishul for Itsopensource

Posted on • Updated 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');
}

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'
                ]
            );
        })
    );
});

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);
                })
            )
        })
    )
});

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;
        })
    );
});

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));
});
  • 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;
        })
    );
});
  • 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);
        })
    );
});
  • 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);
            })
    });
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;
            });
        })
    );
});
  • 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');
        })
    );
});

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)

This post blew up on DEV in 2020:

js visualized

πŸš€βš™οΈ JavaScript Visualized: the JavaScript Engine

As JavaScript devs, we usually don't have to deal with compilers ourselves. However, it's definitely good to know the basics of the JavaScript engine and see how it handles our human-friendly JS code, and turns it into something machines understand! πŸ₯³

Happy coding!