Intro into ServiceWorkers

0

The first baby steps..

This is the first of a three part blog series. Each of these blog posts explain a small part of the ServiceWorker API. In this part, we begin with the basics.

From mobiForge: ServiceWorkers have been called ‘the best thing since XHR’. Web notifications (made possible by ServiceWorkers) go even further than that.

From mobiForge: ServiceWorkers have been called ‘the best thing since XHR’.
Web notifications (made possible by ServiceWorkers) go even further than that.

Even though ServiceWorkers are still a ‘working draft’, they are here to stay. Firefox, Chrome and Opera already have support, with support in Edge coming soon.
But before we dive in, let’s first answer a few basic questions about ServiceWorkers.

What are ServiceWorkers?

When your browser wants to show any page, it will send an HTTP request to the server. This request will normally return with a page. With any number of follow up requests to get extra resources needed for that page.

A simplified depiction of a HTTP request for a page.

A simplified depiction of a HTTP request for a page.

But what if you’re offline? Then your browser will try, but fail miserably at fetching anything. Even if your web application keeps it’s data cached offline, it will need to fetch the HTML from somewhere to start.

That’s the basic use case for ServiceWorkers. It’s basically a proxy, right in the browser. So if the browser is offline, you can simply serve everything you need from the cache (assuming you cached everything).
Every request can be caught by the ServiceWorker and handled any way it wants to handle it, all written in good old JavaScript.

An installed ServiceWorker acts as a proxy for every browser HTTP call for that domain.

An installed ServiceWorker acts as a proxy for every HTTP call for that domain.

And if the browser is offline, the ServiceWorker can use it's own cache.

And if the browser is offline, the ServiceWorker can use it’s own cache.

Notifications

And what if you are waiting for that all important Facebook message. Do you really need to keep your Facebook tab open?
Once again, ServiceWorkers to the rescue. ServiceWorkers can periodically fetch updates and send them to your application or a notification API (notifications in the lock screen of your phone for example). Even when there is no active browser window

A couple of companies already use this API to enhance their user experience. Some mainly for offline behavior (like the Chrome New Tab page) and some as a basis for push notifications (like Facebook).

An example of Facebook web notifications on Android, as you can see the source is the website: m.facebook.com.

An example of Facebook web notifications on Android, as you can see the source is the website: m.facebook.com.

What’s the difference between ServiceWorker and AppCache?

The goal of the two API’s is essentially the same; make a website work offline.

AppCache does this with a manifest file. This manifest states all files that should be cached. The browser does this and any time you go to that page, the AppCache will serve the cached files.
There are a lot of caveats with this API though. Most of those are described in this article.

As the AppCache works with a manifest, it is also static. There is no way to cache anything that isn’t a static file. So if your web app has AJAX requests, it will have to handle those manually in case the app is offline.
This is why ServiceWorkers were introduced.

Tips

There are a couple of things you should know before you start playing with ServiceWorkers. Some are trivial; you need to know JavaScript and basic HTTP and HTML. But what else should you be aware of?

  • You need to know the ES6 Promise API.
    ServiceWorkers are always async. Everything it does must be non-blocking (which is pretty obvious, since blocking code would also block all other HTTP requests). So all the API’s you can call in the service worker, that could take even a little while, will return a promise.
  • ServiceWorkers only work with trusted sources, so https or localhost.
    Since the ServiceWorker can manipulate all of the http traffic on a particular domain, it’s probably best that it is as secure as possible.
  • If you are debugging service workers in Chrome, make sure the ‘disable cache’ flag isn’t set in your developer tools. This will disable the ServiceWorker.
  • If for some reason anything went wrong with your ServiceWorker, you can see its information and delete it from the ‘Resources’ tab in the developer tools in Chrome.
    Or the about:serviceworkers page in Firefox.
  • In Chrome; don’t worry about the error message in the console net::ERR_FILE_EXISTS. This error is thrown when you register the same service worker twice.
    There are ways to prevent a ServiceWorker from being registered twice, but we’ll get back to that later. For now, you can ignore this error.
    This is actually an active issue in the chromium project.

On to the good stuff

After all the disclaimers and information, it’s good to see a ServiceWorker in action. The first example I will show you is the most basic version of a ServiceWorker. The full example is available here on plunker.
No one will ever use a ServiceWorker this way, but it shows the basics nicely.

Everything you do with ServiceWorkers from inside your page or app is done with the ServiceWorker Object on navigator.
So to register a ServiceWorker, you call:

script
    navigator.serviceWorker.register(‘service-worker.js’);
/script

As with everything in the ServiceWorker’s world. This returns a Promise. It will resolve or reject depending on the success of the registration.

Of course we want the ServiceWorker to do something. So in the ServiceWorker we will listen to a ‘fetch’ (an http request). This is an event listener on the ServiceWorker global scope, so can be used like this:

this.addEventListener('fetch', handleFetch);

With this listener we can intervene on this fetch. This listener supplies us with a FetchEvent. Based on this event we can decide what to do with it.
To help us, the event carries the original request, on which we can look at the method or url for example. It also has an isReload property, to let us know if the request came from a deliberate reload by the user (through the refresh button for example).

If we don’t want to do anything with the request, because it’s a POST to our api for example. We don’t have to do anything more. Doing nothing will let the request continue as if nothing happened.

But that’s no fun, what if we do want to change the request? Then we call respondWith() on the request. This stops the original request and lets us determine the response. We can respond directly with a resource or with a Promise of one. So our function could look something like:

function handleFetch(event) {
	event.request.respondWith(myStandardResponse);
}

The example is way too basic for any real world application, of course, but it’s a start. You can see this in action here on Plunker. There we have altered the response from the ServiceWorker in a way that you can see when the response is coming from the ServiceWorker and when it isn’t.

The next part is about something more practical, caching with a ServiceWorker. Check it out here!

About Author

Merijn studied Electrical Engineering at the TU/e, where he started programming in C/C++. After his studies he got involved in several software development projects, using a wide array of programming languages like JavaScript, Go, Dart, Ruby on Rails and PHP. Since he started working at AMIS, Merijn's main focus has been Web Development.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.