 Have you written a couple of small PWAs and want to do more? Hi, I'm Sarah Clark, and I'm here to unpack the mysteries of the service worker. You may have created your service workers by copying some code or using Workbox. And Workbox is normally the best way to handle caches. But when you start building a more complex application, you may want to handle push messages, background sync, or do other work in the background. You'll need to know how to program this in the service worker. A service worker is a client-side programmable proxy between your web app and the outside. Service workers are a type of web worker, and each executes its script separately from the main browser thread. Your service worker has a lifecycle independent of your web app. It can receive messages when not active, either because your application is in the background, not open, or the browser is closed. The service worker is used to intercept network requests. You might intercept requests for your site's HTML and serve them from a cache. You might choose to treat requests for your site images differently. Let's set up a service worker. We need two files, our app's file and a service worker control file. Both of these are in JavaScript. In this example, main.js is our web app, and sw.js is the service worker. First, you need to register your service worker from your web app. Registration tells the browser where your service worker is located and to start installing it in the background. This code starts by checking for browser support. It attempts to find the service worker in the navigator object. If this fails, we'll log a warning and exit. If we have support, call navigator.serviceworker.register. This returns a promise that resolves when a service worker has been registered successfully. We're writing a message to the console after registration to make debugging easier. You can save the registration for later use or retrieve it from the service worker at any time. You can attempt to register a service worker every time the page loads, and the browser will only complete the registration if the service worker is new or has been updated. Otherwise, the existing service worker will remain active. The service worker file normally lives at the top level of your web app next to index.html. This sets the service worker's scope to cover your whole app. The service worker only intercepts network requests within its scope. The default scope is the path to the service worker file and extends to all lower directories. So if the service worker script, for example, serviceworker.js, is located in the root directory, the service worker will control requests from all files at this domain. What if you want the service worker to reduce its scope? You can also pass in an object at registration with an arbitrary scope. A service worker cannot have a scope above its own path. This means that you cannot move the worker under slash scripts and set up a scope up to the root. In this case, we are setting the scope of the service worker to slash app slash, which means the service worker will control requests from pages under slash app slash and below, but not from slash app itself or pages that are higher. Let's take a step back and look at how service workers use promises, beginning with registration. Notice the use of .then. Registration happens in the background, returning a promise. Calling .then on the promise sets up the next action to return after the registration succeeds. Also notice that register passes its result, the registration object, into the next action. Promises act like a pipeline. Once a function creates a promise, you can call .then to register the next action. The outcome of the promise will be passed into this function. The output of that function is either a promise or a value. If it's a value, it will be wrapped in a promise of its own. This lets you chain actions together, starting with a promise and building a pipeline of functions that successively transform the result. In this case, register returns a promise. When the promise resolves, the result is passed into the next function, the one we registered using .then. The code looks like this. We call register, call .then on the promise and collect the registration. We're then using the registration to print out the scope. Okay, so we've covered registration from the web app, but what's happening in the service worker? Remember that the service worker has its own lifecycle independent of your web app. Registering a service worker triggers the installing phase. This creates the service worker and sends it an install event. Inside the service worker script, you add a handler to listen for the install event. Notice the use of the self constant. Inside a worker, this refers to the worker. Outside of a worker, self is another name for window. If you're using ES 2015 or later, you can use the fat arrow notation to create the handler function. Take a moment to study this as we will use both old and new function declarations in our sample code. Now that we have an install event handler, what should we do with it? This is the time to build your main offline cache. This is called pre-caching. Your app downloads the files it needs to run and places them in a cache. Most apps then use this cache in place of the network. Since the files are stored locally, this gives you instant loading. Let's fill in the install event handler. Every cache has a name, so we'll define that. We then list all the files needed to start the app. This list has both index.html and slash, as those are two ways of referring to the same file. Now that we have a list of files, let's cache them. This might look complicated, but let's take it from the inside out. At its heart, this event handler opens the cache and adds all of the files. Each step happens asynchronously and returns a promise. That leaves us with a bit of a problem. If the handler completes before the cache is ready, the next step won't be able to use the cache. So the handler has to wait for the add all step to complete. Calling event.waituntil waits for the promise to resolve and returns the promise's result. In other words, we just converted an asynchronous call back into a synchronous call, and this completes the install event handler. The next event is the activate event, which is sent after the install event completes. We can ignore that event for now. You can use activate as a signal to update your cache. We have to implement one more event handler, the fetch event. This triggers when the service worker intercepts a network request. We will try to satisfy this request using the cache. The code to do this is simple. Fetch uses request objects and response objects. The cache contains a list of requests and matching responses. So we ask the cache to look up the request and return the response or null. If the file isn't in the cache, you can add some code to fall back and try the network. If the match returns null, this will run the fetch request. Finally, wrap this in event.respondwith. This tells the browser you're overwriting it's built in fetch handler. If you're following along in your own browser, load up your page and test it out. Remember that you have to have a web server running and it has to use HTTPS unless you are on local host. You may want to go back to the offline QuickStart lab and run through it again using what you know now or take a plain website and use this simple technique to work offline. If not, keep watching as we dive into promises and fetch. You'll be a master in no time. Thanks for watching and I'll see you in the next lesson. Bye.