Get to know service worker and how to use it
- select the contributor at the end of the page -
Service worker is a game-changing API that will allow for the development of new types of web applications. Let’s talk about what it is and why you should get to know it.
What is service worker?
The name “service worker” doesn’t really say much about this API’s purpose, but there are some good reasons for the name that we’ll revisit shortly. That aside, I think the best way to understand it is to dive in with a simple example of how it’s used. In our example we’ll do three things:
- Register a new service worker
- Intercept any requests the user makes from this page
- If a request matches a specific url, we’ll return our own content instead of what was requested
Registering a service worker
When a user visits our page the first thing we’ll do is install the service worker. Installing a service worker is a simple operation involving a single line of JavaScript. First, create a new file called index.htm with the following contents: <!doctype html>
Service worker example <script> var sw = navigator.serviceWorker.register('service-worker.js', {scope: "./"}) </script>
Add in the following hyperlink while we’re working with index.html, as it will become important later on: <a href="catchme.html">Test Link</a>
ServiceWorker.register method takes two parameters. The first is the path to the script that defines the service worker and the second is the scope (this restricts where in the site structure the service worker can operate). The register method returns a special object (a promise) that can be used to unregister the service worker. In order to make full use of service worker you’ll need to become familiar with the concept of promises and async programming. One thing that makes service worker so interesting is that once it’s installed it exists outside the page. This means that it can be utilized again whenever the user navigates to the page, even if the page is offline. Sites can register multiple service workers and, for now, there's no defined limit on the number a site can register (although there probably will be soon, so don’t get carried away). It’s important to note that service workers can be started and shutdown at any time and are shared across tabs. This means you don’t want to keep state within them, as weird and odd things will happen.
Upgrading a service worker
Upgrading a service worker is simple. When the user revisits the site defining the service worker, the browser conducts a binary comparison of the current worker and the new referenced version. If a new version is found, the browser waits until the original service worker is no longer running and will then install it. There are also a number of events and methods you can hook into if you need more control or information about the installation status.
Defining the service worker
OK, let’s get a little more in-depth. Below are the contents of our service worker: this.onfetch = function(event) { var url = decodeURIComponent(event.request.url), urlToMatch ='http://localhost/swexample/catchme.html', responseText = 'request caught by service worker'; if(url===urlToMatch){ event.respondWith(new Response(responseText)); } };
This service worker hooks into the onfetch event that occurs when any resource is requested from the site – this could be anything from a user clicking a link to another page in the site to a referenced image, JavaScript or CSS file. But we don’t want to deal with every request, so we’ll detect if the url matches a specific string. If it does, we’ll return our own result, which will be the string, “request caught by service worker.” In this case, I’m checking for the url where I defined my site (http://localhost/swexample/catchme.html), so you might need to modify this for your setup. Next, you’ll need to install the 6000 line library – no, I’m kidding! That’s it, really. OK, back to business. Open a browser, check that you’ve enabled the experimental service worker feature and navigate to the example you created. If you click the hyperlink created earlier, you should get the text, “request caught by service worker.” If you don’t see it, make sure you’ve enabled the service worker feature, and that you’re using a browser like Chrome Canary. If that doesn’t do the trick, check the console for messages, as it’s certainly not impossible that the API has changed (it did a few times during the creation of this article). You should now have a service worker that will respond with pre-defined text for specific urls in a tiny amount of code.
When should I use service worker?
You probably have a few scenarios in mind already for why you might use this, but there are three main situations where I think service worker is particularly helpful:
- Offline applications
- Performance
- Notification/mobile sites (in future)
Offline applications
Probably the most interesting functionality that service worker enables is offline applications. Currently, it’s very difficult to write a web application that will function offline. At the moment, there are two main technologies you can utilize for offline applications including caching headers and the app cache. You’ve probably come across caching headers before; these allow the server to specify how long the browser (and various intermediaries) should hold content. They look a bit like this: Cache-Control: max-age=0, no-cache, no-store. There are some subtleties and differences with how browsers can handle these and combinations can get a little confusing. With AppCache you reference a manifest file containing a detailed list of resources that the browser should store offline. The contents of the manifest file look something like this: CACHE MANIFEST index.htm styles.css companyLogo.png But AppCache is quite painful to use, due to its declarative nature. It’s also unforgiving; if you make a mistake listing a resource, nothing is cached offline and content will only be updated if the manifest file itself changes. As you can imagine, these issues make the app cache quite tricky to use and are probably at least partly responsible for its slow uptake. Check out this article for an informative rant on the failings of AppCache. Service worker has a number of advantages over AppCache:
- Fine grained programmatic control
- Less fragile than AppCache
- Superior handling of updates to resources and the service worker
We can use ServiceWorker with other technologies to serve up an alternative experience to users working offline. For example, let’s say the user has already visited our site and has the service worker installed, but has just lost connectivity – no issues with service worker! Here’s an overview of how this offline scenario could work:
- User’s connectivity fails
- User opens browser and enters the site address where service worker was previously installed
- As service worker is installed previously in the browser an instance will be spun up
- User makes request for a page
- Service worker intercepts requests for site using onfetch event. The Service Worker can detect if user is offline by trying to make an ajax request or use the somewhat fickle and unreliable navigator.online api (use at your own risk!)
- If the worker detects that the user is offline, it can then serve up alternative content from local storage, indexedDb etc – or even the new Cache API
Performance
Service worker could be used to speed up a user’s browser experience by downloading resources and caching them locally. Jake Archibald has a great demo demonstrating this idea.
Notifications
In the future, service worker could potentially be used to display notifications to the user of specific events occurring in the background when combined with other APIs. This could be important for scenarios such as web site applications pinned to a mobile device screen.
Browser support
Service worker is still new, so if you want to play with the above example, you’ll need to use specific browsers. Your current options include Chrome Canary (and very soon Chrome), Firefox Nightly and Opera. I like Chrome Canary, as it has the best development tool support and some of the Chrome team is behind driving the service worker specification. The Chrome team has also indicated that it intends to ship a subset of service worker features, meaning that if you can control the browser used by your application’s users, you could even utilize some of these features now! The Internet Explorer team has indicated interest in service worker’s development, but nothing is supported yet. Keep an eye out here. Likewise, you can track the current browser support status here.
Enabling service worker In Chrome
Let’s assume you want to play with this in Chrome. You’ll need to do a couple of tasks to enable service worker. First, open Chrome Canary. Now, head here, check the enable feature box and you should be good to go. Also, be aware of the following service worker related features in Chrome:
- chrome://serviceworker-internals allows you to start, stop and remove service workers, which is very useful when you are testing and want to quickly remove old versions
- Inspect: chrome://inspect/#service-workers allows you to debug service workers in the dev tools you know and love. There is also an option to start the debug tools when the service worker kicks off which is very handy
Take note that this tooling is still at an early stage, so a little buggy but still worth checking out.
Restrictions
So, why is it called service worker and not something more fitting like “request interceptor?” Well, service worker actually belongs to a little family of other types of workers including Web worker and shared worker. Workers were meant to do stuff in the background without interrupting the user. They operate on a different thread to the main browser UI, allowing them to perform tasks like complex calculations in the background without disrupting the browsing experience. A good, real world usage of a Web worker is the physics library Physi.js, which uses a worker to perform complex mathematical calculations in the background. As service worker operations are taking place in a different thread to the main browser UI bad things could happen if the user interface/DOM was manipulated by a different thread. So, workers are restricted in the operations they can perform. All types of workers have a number of restrictions, probably the biggest of which is no direct DOM access. To communicate with the Web page, workers can pass messages back and forth using the postMessage method and listen for messages with the message event.
Security
You need a secure connection to serve up Web workers to users. However, this restriction is lifted for local host urls. The thinking behind this is that service workers are a very powerful feature and if an intermediary (e.g. someone on a dodgy network/ISP) were to manipulate the service worker definition, they would have a lot of power. By forcing service workers to be served over https goes some way to reducing this risk. Another security-related area is scope and how to restrict it. For example, imagine a site similar to geocities that is made up of sub-sites and has urls similar to https://www.mysite.com/badHacker. We don’t want anyone from the badHacker sub-site to be able to install a service worker on a sub-site then have it operate on mysite.com. Instead, the service worker should be restricted to the badHacker subdirectory. How exactly this should work is still under discussion with solutions such as http headers proposed.
Bottom line
While service worker API still has a number of security and lifecycle issues that need work (you can even join the conversation directly), it still offers some major benefits. Namely, it will enable the development of a whole new class of web applications, especially in the mobile space. Want to know more about service worker? Check out these links: