In an earlier article of mine, I talked about 4 essential things every PWA must have, which service worker happens to be part of. Service worker plays a very vital role when it’s comes to Progressive Web Apps (PWA), as it is 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 service worker runs in the background. Before we can start using service worker, we must register it as a background process. This is the first phase of the phase of the lifecycle. Since service worker is not currently supported in all browsers yet. When registering a service worker, we must first check to make sure the browser supports service worker. 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 support service worker, that is, if the navigator
object has a serviceWorker
property. Only when it’s supported that we would register the service worker. The register()
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 service worker script, the register()
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 application specific tasks. For example, we could cache our application 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()
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()
wilol 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 theinstall
event handler of the service worker script - If the user refreshes the page
An example of using the skipWaiting()
to active 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:
Conclusion
So 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.
I hope you find this article helpful and let’s continue the conversation in the comments section below.
Source: Scotch.io