Because Performance Matters

Setting up a Service Worker

And Its Subsequent Life Cycle

By Shawn MaustNovember 29, 2016

In the last post, we talked about some of the benefits that service workers can provide. And we did so in broad, general terms. In this post, we’ll look at the details of how to actually set up one up. We’ll also cover the basics of the service worker life cycle, a concept that is important to understand as we move forward.

Registering a Service Worker

In order to start using a service worker, we’ll first need to register this worker with the browser. This is done using the serviceWorker.register() function.

The following code, for instance, would register a service worker located at /sw.js. Since only certain browsers support service workers, we’ll need to first do a check to see if they are suppoted.

// site.js 

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then(function(reg) {
    console.log(‘sw registered', reg);
  }).catch(function(err) {
    console.log(‘sw error', err);
  });
}

Location matters

One important item to note is that the location of the service worker script matters. If it is located within a certain directory, it will only have access to pages within the same directory. For instance, if I register /app/sw.js as a service worker, it would only have access to files whose URLs start with /app/.

Basic Life Cycle

When the register() function is called on a servicer worker, the script is downloaded and then goes through 3 distinct stages: 1) installing, 2) waiting (if necessary), and 3) active. (MDN has a helpful graphic of the various stages of the service worker life cycle)

Installing

The first step for the browser is ‘installing’ the service worker. If we want to have specific code run during this stage – say, to set up some worker-specific resources – We can set up a listener for the install event and run our code then. We can also use the event.waitUntil() function to extend this install stage until a specified promise is fulfilled.

// sw.js

self.addEventListener('install', function(event) { 

  // Service worker being installed

  event.waitUntil( 

    // We can also cause the 'install' stage to extend 
    // until a promise is fulfilled

  );
});

Waiting (if necessary)

Once the worker is installed, it may be necessary for it to wait before it’s allowed to control pages within its scope. This would happen, for instance, if another service worker has already been installed and is active on these same pages.

What About Updating a Service Worker?

Knowing about this potential ‘waiting’ stage is valuable when we decide to update the code of an existing service worker. Just because we update the code doesn’t mean the browser automatically gives this updated script control of the page.

Rather, if it sees that the service worker code has changed, it will go ahead and ‘install’ this new version. But by default, it will continue to use the the previous version to control the pages within its scope until all the tabs using that version are gone. (This video by Jake Archibald gives a good demonstration of this.)

Now, there are ways to get around this. A hard refresh (shift + refresh), for instance will cause the browser to use the new version. Or, you can use the event.skipWaiting() function during the ‘install’ stage to cause it to jump directly to the ‘active’ part of the life cycle without the need for the currently controlled pages to be closed.

Active

Once the worker has been installed, and there are no other workers that it is waiting on, it enters the ‘active’ phase. Like the ‘install’ event, we can set listeners to execute code when this stage is reached.

self.addEventListener('activate', function(event) {

  // Code for when service woker is activated

  event.waitUntil( 

    // We can also cause this stage to extend 
    // until a promise is fulfilled

  );
});

Gaining Control

Congratulations. The service worker will now control the pages within its scope. But there is one caveat: It will only do so for pages loaded after the initial register() succeeds. Pages that are already open, including the one that did the initial register() call, would need to be reloaded in order to be controlled.

Some Tools

When it comes to working with service workers, Chrome has some useful tools that can help in better understanding what is taking place within the browser. By going to either chrome://serviceworker-internals/, or to Chome’s Dev Tools > Application > Service Workers, you can see the status of the various workers that are active. You also activate workers that are in waiting (i.e. skipWaiting()), and even unregister (remove) workers that are active.

Using tools like these when working with service workers can help illuminate what is happening under the hood.

Neccessary First Steps

Granted, we haven’t really done anything useful with service workers yet. But getting an understanding of how to register one, and then the life cycle of that service worker, are important first steps in that direction. In the coming posts, we’ll be looking at specific ways to leverage service workers (e.g. resource caching, offline use) once they’ve been registered and activated.