Tutorial

Demystifying The Service Worker Lifecycle

Published on December 12, 2019
    author

    Chimezie Enyinnaya

    Demystifying The Service Worker Lifecycle

    Introduction

    Service workers play a very vital role in Progressive Web Apps (PWA), as they are responsible for offline caching, push notifications, background sync etc. In this article, we’ll be demystifying the service worker lifecycle and what can be done at each stage of the lifecycle.

    For effective use of service worker, an understanding of the service lifecycle is essential. The service worker lifecycle consists of mainly 3 phases, which are:

    • Registration
    • Installation
    • Activation

    Let’s go over each of them.

    Registration

    A service worker is basically a JavaScript file. One thing that differentiate a service worker file from a normal JavaScript file, is that a service worker runs in the background, off the browser’s main UI thread. Before we can start using service worker, we must register it as a background process. This is the first phase of the lifecycle. Since service workers are not yet supported in all browsers, we must first check to make sure the browser supports service workers. Below is a code we can use to register a service worker:

    app.js
    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('/sw.js')
        .then(function (registration) {
            console.log('Service worker registered!');
        })
        .catch(function (err) {
            console.log('Registration failed!');
        })
    }
    

    First, we check if the browser supports service workers, that is, if the navigator object has a serviceWorker property. Only when it’s supported would we register the service worker. The register() method takes the path to the service worker script and returns a promise.

    At the point of registering a service worker, we can also define the scope of the service worker. The scope of a service worker determines the pages that the service worker can control. By default, the scope is defined by the location of the service worker script.

    app.js
    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('/sw.js', {
            scope: '/blog/'
        })
        .then(function (registration) {
            console.log('Service worker registered!');
        })
        .catch(function (err) {
            console.log('Registration failed!');
        })
    }
    

    In addition to accepting the path to the service worker script, the register() method can also accept an optional object, where we can define the scope of the service worker. Here, we define the scope of the service worker to /blog/, which will limit the service worker to only the blog directory.

    Installation

    The fact that a service worker has been successfully registered doesn’t mean it has been installed. That’s where the installation phase of the lifecycle comes into play. Upon successful registration of the service worker, the script is downloaded and then the browser will attempt to install the service worker. The service worker will only be installed in either of these cases:

    • The service worker hasn’t been registered before
    • The service worker script changes (even if it’s by one byte).

    Once a service worker has been installed, an install event is fired. We can listen for this event and perform some application0-specific tasks. For example, we could cache our application’s static assets at this point:

    sw.js
    const assetsToCache = [
        '/index.html',
        '/about.html',
        '/css/app.css',
        '/js/app.js',
    ]
    
    self.addEventListener('install', function (event) {
        event.waitUntil(
            caches.open('staticAssetsCache').then(function (cache) {
                  return cache.addAll(assetsToCache);
            })
          );
    });
    

    Here, we are using the open() method of the Cache API, which accepts the name of the cache (staticAssetsCache in this case) to either open (if it already exists) or create and returns a promise. Once the promise is resolved, that is, inside the then(), we again make use of the addAll() of the Cache API, which accepts an array of URLs to cache. Since the open() method will return a promise, we need wrap it inside event.waitUntil(), which will delay the installation of the service worker untill the promise is resolved. If the promise is rejected, the install event fails and the service worker will be discarded.

    Activation

    If the installation was successful, the service worker enters an installed state (though not yet active), during which it waits to take control of the page from the current service worker. It then moves on to the next phase in the lifecycle, which is the activation phase. A service worker is not immediately activated upon installation. A service worker will only be active (that is, be activated) in any of these cases:

    • If there is no service worker currently active
    • If the self.skipWaiting() is called in the install event handler of the service worker script
    • If the user refreshes the page

    An example of using the skipWaiting() method to activate a service worker can look like below:

    sw.js
    self.addEventListener('install', function (event) {
        self.skipWaiting();
    
        event.waitUntil(
               // static assets caching
          );
    });
    

    An activate event is fired upon a service worker being active. Like the install event, we could also listen for the activate event and perform some application specific tasks. For for example, clearing out the cache:

    sw.js
    const cacheVersion = 'v1';
    
    self.addEventListener('activate', function (event) { 
        event.waitUntil( 
            caches.keys().then(function (cacheNames) {
                cacheNames.map(function (cacheName) {
                    if (cacheName.indexOf(cacheVersion) < 0) { 
                        return caches.delete(cacheName);
                       } 
                    }); 
                });
            }) 
        ); 
    });
    

    The snippet above loops through all the named caches and deletes any existing if the cache does not belongs to the current service worker.

    Once the service worker has been activated, it now has full control of the pages. With the service worker active, it can now handle events such as fetch, push and sync.

    sw.js
    
    self.addEventListener('fetch', function (event) {
        event.respondWith(caches.match(event.request))
        .then(function (response) {
            return response || fetch(event.request);
        });
    });
    

    If the service worker after being active, does not receive any of the functional events mentioned above, it goes into an idle state. After being idle for some time, the service worker goes into a terminated state. This does not mean the service worker has been uninstalled or unregistered. In fact, the service worker will become idle again as soon as it begins to receive the fuctional events.

    Below is a visual summary of the service worker lifecycle:

    The Service Worker Lifecycle

    Conclusion

    In this article, we looked at the service worker lifecycle, the events that are emitted at end phase of the lifecycle. Also, we looked some possible things we could with a service worker by hooking into some of these events.

    Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

    Learn more about our products

    About the authors
    Default avatar
    Chimezie Enyinnaya

    author

    While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

    Still looking for an answer?

    Ask a questionSearch for more help

    Was this helpful?
     
    1 Comments
    

    This textbox defaults to using Markdown to format your answer.

    You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

    Is this part wrong? In the “Activation” section, where you’re talking about when the service worker becomes activated, one of the mentioned cases is:

    • If the user refreshes the page

    But I tried this by adding an event listener on the “activate” event, and it runs only once after the installation, and not anymore, specifically not after hitting subsequent refreshes… (Thanks for the article).

    Try DigitalOcean for free

    Click below to sign up and get $200 of credit to try our products over 60 days!

    Sign up

    Join the Tech Talk
    Success! Thank you! Please check your email for further details.

    Please complete your information!

    Become a contributor for community

    Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

    DigitalOcean Documentation

    Full documentation for every DigitalOcean product.

    Resources for startups and SMBs

    The Wave has everything you need to know about building a business, from raising funding to marketing your product.

    Get our newsletter

    Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

    New accounts only. By submitting your email you agree to our Privacy Policy

    The developer cloud

    Scale up as you grow — whether you're running one virtual machine or ten thousand.

    Get started for free

    Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

    *This promotional offer applies to new accounts only.