Exploring Service Workers

Inspecting Service Worker Lifecycle

Kyle Simpson

Kyle Simpson

You Don't Know JS
Exploring Service Workers

Check out a free preview of the full Exploring Service Workers course

The "Inspecting Service Worker Lifecycle" Lesson is part of the full, Exploring Service Workers course featured in this preview video. Here's what you'd learn in this lesson:

After demonstrating how to use the developer console to inspect service workers, Kyle analyzes the lifecycle of a service worker by pointing out the phases passed through during creation, stopping, and starting.


Transcript from the "Inspecting Service Worker Lifecycle" Lesson

>> Kyle Simpson: There's another nuance to this life cycle. And if you're starting to get a little bit overwhelmed by all these life cycle nuances, you're in good company. It's a lot more complex than it was with just a regular web worker. The web workers there and then the web worker's dead and then it's back and then it's dead.

There's a lot of complexity here, and it's because of all the things that we're potentially breaking about web experience by installing a service worker. We have to be able to allow the author of the service worker to handle all the different cases, and that's the reason for this complexity.

But your service worker being activated does not mean that, like when we did the self.skip waiting, it doesn't mean that a page that was talking to the old service worker immediately knows about the new service worker. So you may have a page instance for example, imagine you had three tabs open and you've loaded up a new tab and we've said skip waiting, I've got this new service worker.

But what about those other two tabs that are still thinking they're talking to and controlled by that old service worker, which is now gone. So one of the complexities that we need to handle is we essentially need to tell the page, hey, I'm controlling you now. And this is what actually fires that controller change event that we've talked about.

And the way we do that is called clients.claim. Clients is plural because it's basically saying go find all my clients. This is actually an API that you could cycle through all of the connected clients and do this for only some of them if you really cared. I can't imagine any use case why you wouldn't wanna claim all of the open clients, but maybe there's some things there.

Just for the consistency of it, since this has not activated until after we have claimed all of these, and that is an asynchronous event, we're gonna await the clients.claim, and then that's when we're gonna print the service worker is activated. This one doesn't need to be in a sync function anymore.

You can leave it as one if you like the consistency of it. But the reason and this is a little nuance of the way promises work. But the reason that we need this is that we need a promise to pass to this thing. And we can't really construct unless you did it the manual way like making, like doing a new promise that's passed in and then doing the work inside of it.

We can't really have this thing being an async function and say event that wait until myself. So that's why I have it in a separate function called handleActivation that can do all of my asynchronous stuff. And I get one promise that rolls up all that behavior and says that's all done.

So that's the reason for splitting this out. I've heard other people say that they like to do inline async function expressions here, like an async iffy. I just like to have stand alone function declaration, which is why I did it here. But you could either do that or just do an inline async if that's more of your style.

Okay, well I think that's it for setting up our service worker. So let's actually try it, let's check and see if we can make this work. Make sure your files are saved. Come over here to the browser and before you actually refresh the page, I wanna direct you to the application tab in your developer tools.

This is where you're going to spend a lot of time when you're working on service workers. And there's a couple of things to point out. There's a service workers item here and you'll notice that there's three check marks. These are ones that you can control the service worker behavior for.

We're not going to get too much into them. There's a lot of Chrome documentation in some of those links that I pointed you to and the readme. There's a lot of documentation about the implications of this. The reason I don't use this one very much is because it's really easy to leave that on.

And then you're trying to do something with your service worker and nothing's happening and you forgot this check mark was on. I literally wasted like three days one time on a project where I was like, why is this stuff not, I'm updating my service worker. I can see the new service worker.

Why isn't it doing what I want with this item? And then it was because I had this check mark on and the browser was just bypassing it. So use it with caution and make sure to remember you turn on something like that mode. This one I'm pretty sure is now a defunct option because I believe that is the default now, that it always updates service worker.

It used to be that it used the browser cache, now I'm pretty sure it does it all the time. So, I don't even think we need that check mark anymore. And this one is not one I've ever used because I use the network tab to force offline, but this can force just your service worker into an offline mode.

I've never needed my service worker offline, but my browser online. But that may be an use case you might need. When your service worker has installed itself, there's gonna be a bunch of stuff that we see here that we don't see. And when we start adding items to our cache, it's gonna be listed here and there's a few of these other ones that we'll end up looking at later.

By the way, if you never knew, this is where you can inspect any items in local storage on a page. So, application tab is actually a pretty important tab to check out. Anyway, let's go back to our console. Well actually, let's stay on the application tab and let's go load our page.

Let's do a refresh and now, we see that we have a service worker installed. It's given a unique ID, which if you are doing a lot of rapid updates you might pay attention to that changing, and if you don't see that number changing it's because your service worker isn't getting installed.

One thing to know is if you have an error in a service worker, you definitely will get a message in your console. But it's real easy, if you've got a bunch of console messages, to miss that stuff. So one thing you wanna have like an eagle eye attention to is, if you're trying to make a change to your service worker and it doesn't seem to be taking, it might be because it's not loading at all.

The protocol for service workers is if there's any error on installation, it throws that service worker away and keeps the old one. So I've had this happen where I've been trying to make a change and I didn't realize there was some syntax error that was causing it to never get installed.

So, just be aware of that. Remember, I said the idea that we can mess around with our service workers. One of the things that we can do is start and stop our service workers. Before you click that though, let's go to our console. And see that we saw service worker version 1 is starting, installed, and activating.

But now, let's come back to our Application tab and click Stop. That's mimicking what might have happened if the browser decided, I don't need the service worker anymore. And then if we click Start again, it's like then coming back to a page or reviving a page that was already open.

And you'll notice that when we go back to the console, we got another indication of that service worker is starting. So we didn't really go through the installation and activation but we did redo any of our starting initialization stuff. So beware of what that means for the status of things.

If you have something that you need to persist across those, you're gonna have to store it somewhere, like for example in index db. This is a little bit strange, I don't know why, but service workers don't have access to local storage. So you can't store stuff in local storage, but they do have index db and you can store stuff in index db, okay?

So if you do have a piece of state that you need to store across indications of your service worker, remember that. But if you start doing persistent storage remember that you need to be cleaning up after yourself for you to eventually run the browser out of its quota and then you won't be able to store anything.

>> Kyle Simpson: Okay, so now we have our first service worker written. It's not doing anything particularly interesting yet, but give yourselves a pat on the back. You've now written your first service worker. Any questions before we move on?
>> Speaker 2: I noticed you don't tend to use arrow functions very often or at all.

Is there a reason for that? Does it cause a lot of issues or is it not compliant or?
>> Kyle Simpson: I glad you said that at all because I don't use arrow functions at all.
>> Speaker 2: Okay, [LAUGH]
>> Kyle Simpson: Yeah, I'm very much not a fan of arrow functions.
>> Speaker 2: Okay.

>> Kyle Simpson: And the reasons for that are outside of our discussion scope here, but it's essentially a readability thing. It's an anonymous function expression and I think it communicates less than when a named function. When I have a function with a name. So this could have been like an anonymous arrow expression iffy thing.

But the fact that I want to tell you that it's handling activation I think that name makes my code more readable. So I'll use function declarations when they're gonna be multiple lines and this one is. Or if it's just gonna be a one liner I'll do an in line function expression but I still give it a name.

>> Speaker 2: Got you.
>> Kyle Simpson: Because in my mind, every function, if it exists in your program it has a purpose. And if it has a purpose it has a name, and the user shouldn't have to read the code in the function to figure out it's purpose. You should just tell them what the purpose is.

>> Speaker 2: So it's a readability constraint, not a technical constraint.
>> Kyle Simpson: It is, yeah.
>> Speaker 2: Okay.
>> Kyle Simpson: Well there are technical reasons why arrow functions may or may not be what you want.
>> Speaker 2: Okay.
>> Kyle Simpson: There are technical behaviors like with this keyword, but my primary reason for generally avoiding them is I don't like to have poor readability.

>> Speaker 2: Okay. In blog JS, the IT Service Worker function that needs to be asynchronous because the register method?
>> Kyle Simpson: Because we're doing an await right here.
>> Speaker 2: Okay, and that-
>> Kyle Simpson: The register method is asynchronous, and we wanna wait on that before moving on.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now