Can I use service workers for my website?
Tags: webperf, serviceworkers, progressivewebapps, cacheapi
Published: 2020-06-11 08:36:54

## Intro to service workers

So you probably landed here because you do not use service workers in your app and you want to know how they
can help you.

<div style="width: 100%;text-algin:center;">
  <img
    src="https://media.giphy.com/media/L1Es4zQr2Vcfo73o4P/giphy-downsized.gif"
    title="man saying yeah"
    alt="Gif showing man saying yeah"
  />
  <a
    target="_blank"
    href="https://giphy.com/gifs/cbs-ncis-new-orleans-ncisnola-cbs-L1Es4zQr2Vcfo73o4P"
  >
    via GIPHY
  </a>
</div>

No need to worry. We go through all the service worker API in detail.

I posted this article initially on my [blog](https://marcradziwill.com/blog/can-i-use-service-workers-for-my-website/).

---

If you like this article, smile for a moment, share it, follow me, check out my RSS feed and [subscribe to my newsletter](https://marcradziwill.com/newsletter/).

---

## Tl;dr

In this post, I try to outline the main functionality of service workers, and it's lifecycle. I talk about why I think that every website or web app should make use of service workers. You find all the resources for this service worker tutorial on [GitHub](https://github.com/marcradziwill/service-worker-tutorial).

{% github marcradziwill/service-worker-tutorial %}

<hr />

## Table of Contents

1. [Why can you use service workers for you website?](#whyuse)
2. [What is a service worker?](#whatisserviceworker)
3. [What are the use cases for Service Workers?](#usecases)
4. [Service workers events and lifecycle?](#lifecyleevents)
   - [Events](#events)
   - [Lifecycle](#lifecycle)
     1. [Installing](#installing)
     2. [Installed](#installed)
     3. [Activating](#activating)
     4. [Activated](#activated)
     5. [Redundant](#redundant)
5. [How to register service worker?](#register)
   - [Take care of the scope!](#scope)
6. [Event handlers of service workers](#eventhandlers)
   - [How to install a service worker - The install event](#installevent)
   - [How to update service worker cache - The activate event.](#activateevent)
   - [How to intercept network requests - The fetch event](#fetchevent)
   - [How to sync data in the bachground - The sync event](#syncevent)
7. [Service worker and Push Notifications](#swpush)
   - [Notification](#notification)
   - [Push API](#push)
8. [How to unregister service worker](#unregister)
9. [How to debug a service worker](#debug)
10. [Conclusion](#conclusion)

<hr />

## 1. Why can you use service workers for you website? <div id="whyuse"></div>

In my mind, there are only a few reasons why you don't need a service worker. If your app never requires a network request and your assets are stored locally on your device. Maybe this is a rare example, but if you don't need a network request,you can not intercept anything.

In any usual case of a web app or website, you can use service workers. Your users will thank you for it and maybe even buy your excellent product because you delivered your site fast.

## 2. What is a service worker? <div id="whatisserviceworker"></div>

A service worker is a script that your browser runs in the background. The primary use case is caching by programmatically intercept network requests, but this is not the only feature, with a service worker you can implement push notifications and background sync.

By allowing us developers to intercept all network requests, we can go offline with our web apps and websites. We could do this before with AppCache, but since this API is deprecated, you should go with service workers.

![image showing how a service worker intercept the network request](https://marcradziwill.com/static/5b740f07d994746069d3a71c339a4d8b/8ec0a/service-worker.jpg 'service worker intercepting the network request')

But not only should you use service workers. In my opinion, every website or web app should have a service worker installed. At least to cache resources to make features of your site faster or accessible while you're on a slow network. Thus service workers are not just there for implementing your app as a PWA.

What is a service worker technically: It's a special kind of JavaScript web worker, so it has no access to the DOM. It's like an event-driven programmable network proxy. Service workers use promises in the background. So you should have a minimum of knowledge of the Promises API.

[![Web Performance Checklist](https://dev-to-uploads.s3.amazonaws.com/i/i9nrcwt53letp80a28eg.png)](https://devcademy.marcradziwill.com/web-performance-checklist/)

One of the main advantages of a service worker is that the script runs on a different thread than the regular web page. So no user interaction is blocked by the running worker. A service worker only works over HTTPS or on localhost for security reasons.

## 3. What are the use cases for Service Workers? <div id="usecases"></div>

Use cases for service workers are primary caching. But they offer much more features for us [web developers](https://marcradziwill.com/services/webdevelopment/). Caching is probably the most used feature and the feature you should use. I think this is not a matter of option. By implementing caching with a service worker, you can make the user interaction with your site faster and make it accessible even if the user is not online.

If you cache your assets with a service worker you need to intercept the network requests your app is making. Besides responding to the cached resource, you could even change the whole file you respond. A simple example would be that your application requests an image of a dog, and you send an image of a lama from the service worker. But thinking about this feature brings us to the availability to manipulate any request. I think this is a powerful feature for any developer.

The next use case is the most annoying features: Push Notifications. These are two technologies: Push and Notification. Notification is the one we all know and decline every day. You can send notifications to your user using a service worker. I don't mean that the technology behind Notifications is terrible, but more the way we developers implement them or how the requirements engineers like to have them: An possibility to send notifications to our users.

We can trigger him even if he is not on our site. But the main problem is that this is super annoying. I do not even think about what an application could send me if they ask me 20 milliseconds after I visit their site for permission to send me notifications. We could do this in a much elegant way. First, we should show them our product or content, then what we will send them and finally we should tell our users that we will now ask them for permission.

Push is a much more powerful feature than you think. With a service worker, you can receive push messages from a server. To set up Push is complicated, but then you can send push messages from your server to your client (service worker) even if there is no tab open. You can send the new version of your blog article to your users even if they are not currently on your site and your service worker can cache the new article. The service worker responds to the client with your new article without having to make a real network request.

## 4. Service workers events and lifecycle <div id="lifecyleevents"></div>

A service worker has a lifecycle that is separate from your web app. The worker is listening to events you can implement. See a simplified lifecycle in the image below. During installing the `install` event is triggered and while activating the `activate` event.

If your service worker does not receive any events, it goes into an idle state. It is still available but won't use many resources after being idle the state changes to terminated. Still, the service worker is available. If it receives functional events, it starts working again.

![image showing the lifecycle of a service worker](https://marcradziwill.com/static/abeb4dc7ed167f611dfafbac2a31a8ae/0f98f/simplified-service-worker-lifecycle.jpg 'lifecycle of a service worker')

### Events <div id="events"></div>

There are two different kinds of events: Functional events and lifecycle events. The lifecycle events trigger during the installation and activation of your service worker to handle caches, for instance.

You can implement the functional events after the service worker is ready for usage. For example, to intercept and handle network requests.

### Lifecycle <div id="lifecycle"></div>

![image shows the states and events of a service worker](https://marcradziwill.com/static/232df4b476a2368041a12e7ee65c8b52/8ec0a/service-worker-states.jpg 'states of a service worker')

The worker lifecycle contains mainly the following phases or states:

- Installing
- Installed
- Activating
- Activated
- Redundant

#### Installing <div id="installing"></div>

This stage is the beginning of the registration of your service worker. You can define the files to cache or any other setup.
During this phase, the `install` event is triggered.

#### Installed <div id="installed"></div>

The service worker is now ready for your visit and has finished it's setup. The worker waits in this state to take control of the page from the current service worker.

#### Activating <div id="activating"></div>

If the current state is `activating`, it means that there no other worker, and the browser fires the `activate`. It this state, the worker can finish its setup like clearing out old caches.

#### Activated <div id="activated"></div>

The service worker is now ready to handle functional events.

#### Redundant <div id="redundant"></div>

This state indicates that another one replaces this worker.

## 5. How to register service worker? <div id="register"></div>

To install the service worker, we need to register it.
The registration tells the browser to find, download, and parse your service worker after the `load` event. There might be reasons to start your service worker earlier.

Please check [this article](https://developers.google.com/web/fundamentals/primers/service-workers/registration) for further information.

```javascript
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker
      .register('./service-worker.js')
      .then((registration) => {
        console.log('congrats. scope is: ', registration.scope);
      })
      .catch((error) => {
        console.log('sorry', error);
      });
  });
}
```

If the browser successfully loads your the `./service-worker.js` file, it installs it under your domain. Your file contains all event listeners you implemented.

### Take care of the scope! <div id="scope"></div>

A service worker can only access files that are in its directory or a lower one. You can also change the scope and set it to your favourite folder:

```javascript
navigator.serviceWorker.register('./service-worker.js', { scope: '/app/' });
```

## 6. Event handlers of service workers <div id="eventhandlers"></div>

Like I said above, we use event handlers to hook into the service worker's lifecycle and perform our logic.

### How to install a service worker - The install event <div id="installevent"></div>

The browser triggers the install event after the first registration, it is the first event your service worker gets, and it is only called once per service worker. If the worker is updated, the browser calls the install event on a new worker.

You can use this event to cache everything you need before being able to control clients.

Check out the following example. We define a name for the cache with `const CACHE_NAME = 'v1'` and list all the files we want to store in `urlsToCache`.

```javascript
const CACHE_NAME = 'static-v1';
const urlsToCache = ['/', '/js/main.js', '/css/style.css', '/img/image1.jpg'];
```

Now we are going to implement our event handler for the `install` lifecycle event. In this case, `self` is a reference to `window` where we call the `addEventListener` function.

```javascript
self.addEventListener('install', event => {
  event.waitUntil(
    caches
    .open(CACHE_NAME)
      .then(cache => {
        return cache.addAll(urlsToCache);
      });
  );
});
```

Since the `caches.open()` returns a promise, we need to wrap it with `event.waitUntil`. After that, all our files are cached in the browser with the Cache API.

### How to update service worker cache - The activate event. <div id="activateevent"></div>

The activate event is essential when you are updating your service worker file and want to clean the caches.

After your service worker is installed, it waits for clients to take control of the existing service worker. If this happens, the browser fires the `activate` event after the `install` event. For instance, you can use this to remove old caches.

See in the following example how you can hook into this event and use it for your caching strategy. To do so, we add a new array (validCaches) to the worker file.

```javascript
// added array
const validCaches = ['static-v2']

const CACHE_NAME = 'static-v2';
const urlsToCache = [
 '/',
 '/js/main.js',
 '/css/style.css',
 '/img/image1.jpg',
];

self.addEventListener('install', event => {
  event.waitUntil(
    caches
    .open(CACHE_NAME)
      .then(cache => {
        return cache.addAll(urlsToCache);
      });
  );
});
```

In this event handler, we use it to check all caches and delete them if they are not valid.

```javascript
self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches
      .keys()
      .then((keys) =>
        Promise.all(
          keys.map((key) => {
            if (!validCaches.includes(key)) {
              return caches.delete(key);
            }
          }),
        ),
      )
      .then(() => {
        console.log('V2 now ready!');
      }),
  );
});
```

After the service worker is activated, it now has control of the pages, and it can handle events such as fetch, push and sync.

### How to intercept network requests - The fetch event <div id="fetchevent"></div>

The service worker fetch event fires every time your web app makes any request. In the event handler in your service worker, you can intercept the requests and decide what you send back to your web app.

I this example a `cache-first` strategy is implemented.

```javascript
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      if (response) {
        return response;
      }
      return fetch(event.request);
    }),
  );
});
```

In our example above, we tell the browser with `event.respondWith` that we are going to handle the network request. From that moment on, it is on us the make the client happy.

First, we are checking our cache. With `cache.match` we search if we have an entry in the cache that matches the specified request.

If it finds nothing, the promise resolves `undefined`. To have a fallback for that case, we perform the actual network request `fetch(event.request)` and return.

### How to sync data in the bachground - The sync event <div id="syncevent"></div>

The sync event allows you to defer network requests. This feature is useful to ensure that all network requests reach their destination. If the user is online, the sync event fires immediately and perform whatever you implemented. If the user has no connection, the request is deferred and fired as soon as the network is available again.

The sync event allows the deferring of network tasks until the user has connectivity. The feature referrers to an implementation called background sync.
A background sync service worker is useful for ensuring that any network-dependent tasks that a user kicks off during offline mode reach their intended destination when the network is available again.

See the example below. After the service worker is installed, we register one-off sync with `registration.sync.register('myFirstSync')`.

```javascript
navigator.serviceWorker.register('/sw.js');

navigator.serviceWorker.ready.then((registration) => {
  return registration.sync.register('myFirstSync');
});

self.addEventListener('sync', (event) => {
  if (event.tag == 'myAwesomeSync') {
    event.waitUntil(doSomeStuff());
  }
});
```

After that, we write an event handler to listen to all sync events. In our particular case `myAwesomeSync` we perform some stuff in `doSomeStuff`;

```javascript
self.addEventListener('sync', (event) => {
  if (event.tag == 'myAwesomeSync') {
    event.waitUntil(doSomeStuff());
  }
});
```

You can check that out in Chrome in your Developer Tools. You see the service worker running in the `Application` Tab. To test your implemented sync event, check the `offline` box you see in the Screenshot below and reload your page.

![Running service worker in the developer tools console in google chrome](https://marcradziwill.com/static/29d534b7331c853585f449bde88976a3/8f488/running-service-worker.jpg 'Running Service Worker')

If you want to know more about background sync, you can check out these [instructions](https://developers.google.com/web/updates/2015/12/background-sync).

## 7. Service worker and Push Notifications <div id="swpush"></div>

With a service worker, you can use commonly mentioned "Push Notifications". Web Push Notifications are two technologies. It's Push and Notifications. One handy, the other is annoying people every day hundreds of times.

### Notification <div id="notification"></div>

Probably you know what's coming now. I am sure you declined at least one permission today to send you notifications. Many sites request this permission, and most of the time, I just declined it. You can implement these notifications through service workers so you can send the user any notification they might need.

### Push API <div id="push"></div>

The Push API is the REAL cool stuff when it comes to Web Push Notifications. Unfortunately, the permission to send Push Messages is the same as to send Notification. So if the user already declined it, you can not use it.

The cool thing about the Browser Push API is that you can use it to communicate between your browser and the server without having an open tab of your web app. Let's imagine you wrote a blog article about Workbox.js. You published that article, and it gets cached by your service worker.

Next, you edit your article. In a typical case, your browser has to load the updated article and cache it again with your service worker. By using the Push API, your server pushes the updated article right to your service worker in your browser.

The magic even happens if you do not have an open tab of your web app. Your service worker receives the updated article and can update the cache before you even thought about to revisit the blog page.

## 8. How to unregister service worker <div id="unregister"></div>

Sometimes things get wrong, and you want to uninstall or unregister your service worker. You can do this manually for your site in the Application Tap of the Developer Tools in Chrome or any other browser that supports service worker. But this will not help your customers if the service worker bug is already in production.

Unregister, a service worker, looks similar to the register you find above.

```javascript
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.getRegistrations().then(function (registrations) {
    for (let registration of registrations) {
      registration.unregister();
    }
  });
}
```

If you deploy this code, it will unregister the current service worker after it finishes its work. But the method can lead to some problems if your page relies on the cached assets. You can read more about this in a post of [Chris Live - How to Uninstall, Unregister or Remove a Service Worker [With Example Code]](https://love2dev.com/blog/how-to-uninstall-a-service-worker/).

## 9. How to debug a service worker <div id="debug"></div>

You can debug your service worker just like your regular JavaScript code. You can choose if you want to use `console.log`, set the `debugger` keyword in your code or set a breakpoint within the sources-Tab of the Chrome Developer Tools. Don't be confused by order of your logs, as Chrom handles this different sometimes.

If you want to train to debug, I recommend you to go through the codelab of [debugging service workers](https://codelabs.developers.google.com/codelabs/debugging-service-workers/) on the google develops platform.

## 10. Conclusion <div id="conclusion"></div>

You find all the resources for this article on [GitHub](https://github.com/marcradziwill/service-worker-tutorial). Feel free to check it out, try some stuff or fork it.

In this post, I tried to outline the main functionality of service workers, and it's lifecycle. I mentioned why I think that every website or web app should make use of service workers.

If you like this article, smile for a moment, share it, follow me, check out my RSS feed and [subscribe to my newsletter](https://marcradziwill.com/newsletter/).

Cheers Marc

Credits: [Photo by Josue Isai Ramos Figueroa](https://unsplash.com/photos/Pj4je7OjrME) on Unsplash