Difference between clientsClaim and skipWaiting
Asked Answered
S

3

9

Im trying to understand the difference between skipWaiting and clientsClaim. In my understanding: calling skipWaiting will cause the new service worker to skip the waiting phase, and become active right away. clientsClaim can then 'claim' any other open tabs as well.

What I gather from documentation online:

  • skipWaiting skips the waiting phase, and becomes active right away source

  • clientsClaim immediately start controlling pages source

In every post I find online, I usually always see clientsClaim and skipWaiting used together.

However, I recently found a service worker that only uses clientsClaim, and I'm having a hard time wrapping my head around what actually is the difference between clientsClaim and skipWaiting, and in what scenario do you use clientsClaim but not skipWaiting?

My thinking on this, and this may be where I'm wrong, but this is my understanding of it: Is that calling clientsClaim, but not skipWaiting is redundant? Considering:

  • The new service worker will become active when all open pages are closed (because we're not using skipWaiting)
  • When our new service worker is activated, we call clientsClaim, even though we just closed all open pages to even activate the new service worker. There should be no other pages to control, because we just closed them.

Could someone help me understand?

Read documentation on skipWaiting

Read documentation on clientsClaim

Read about service worker lifecycle by Jake Archibald, and played around with this demo

Read a bunch of stackoverflow posts, offline cookbook, different blog posts, etc.

Sommerville answered 20/9, 2019 at 11:17 Comment(0)
P
11

self.skipWaiting() does exactly what you described:

forces the waiting service worker to become the active service

"Active" in this sense does not mean any currently loaded clients are now talking to that service. It instead means that service is now the service to be used whenever a new client requests it.

This is where Clients.claim() comes in:

When a service worker is initially registered, pages won't use it until they next load.

Without calling claim, any existing clients will still continue to talk to the older service worker until a full page load.

While most of the time it makes sense to use skipWaiting and Clients.claim in conjunction, that is not always the case. If there is a chance of a poor experience for the user due to a service worker not being backwards compatible, Clients.claim should not be called. Instead, the next time a client is refreshed or loaded, it would now have the new service worker without worry of the breaking change.

Pomegranate answered 20/9, 2019 at 15:48 Comment(3)
Thanks! That clarifies a lot already. So just making sure I understand this correctly, lets say I have my site open in a tab: tab-a. If I call skipWaiting, and refresh tab-a, the new service worker becomes active, but tab-a is actually still using the old service worker? (e.g.: in dev tools you'll see service worker #3071 as being active and running, but the previous service worker, service worker #3070 i actually still controlling the page? Additionally, what is the usecase for only using clientsClaim but not skipWaiting?Sommerville
The case you described is correct. IIRC you'll actually see both as being active pre-refresh. In regards to the usecase of clientsClaim being used on its own, I can't think of one.Pomegranate
This answer is very misleading, calling self.skipWaiting() does in fact also claim all existing clients. The 'fetch' event will fire for existing clients and clients.matchAll() will return existing clients as well.Bertolde
L
7

The difference between skipWaiting() and Clients.claim() in Service Workers

An important concept to understand is that for a service worker to become operational on a page it must be the controller of the page. (You can actually see this property in Navigator.serviceWorker.controller.) To become the controller, the service worker must first be activated, but that's not enough in itself. A page can only be controlled if it has also been requested through a service worker.

Normally, this is the case, particularly if you're just updating a service worker. If, on the other hand, you're registering a service worker for the first time on a page, then the service worker will be installed and activated but it will not become the controller of the page because the page was not requested through a service worker.

You can fix this by calling Clients.claim() somewhere in the activate handler. This simply means that you wont have to refresh the page before you see the effects of the service worker.

There's some question as to how useful this actually is. Jake Archibald, one of the authors of the spec, has this to say about it:

I see a lot of people including clients.claim() as boilerplate, but I rarely do so myself. It only really matters on the very first load, and due to progressive enhancement the page is usually working happily without service worker anyway.

As regarding its use with other tabs, it will again only have any effect if those tabs were not requested through a service worker. It's possible to have a scenario where a user has the same page open in different tabs and has these tabs open for a long period of time, during which the developer introduces a service worker. If the user refreshes one tab but not the other, one tab will have the service worker and the other will not. But this scenario seems somewhat uncommon.

skipWaiting()

A service worker is activated after it is installed, and if there is no other service worker that is currently controlling pages within the scope. In other words, if you have any number of tabs open for a page that is being controlled by the old service worker, then the new service worker will not activate. You can therefore activate the new service worker by closing all open tabs. After this, the old service worker is controlling zero pages, and so the new service worker can become active.

If you don’t want to wait for the old service worker to be killed, you can call skipWaiting(). Normally, this is done within the install event handler. Even if the old service worker is controlling pages, it is killed anyway and this allows the new service worker to be activated.

Laine answered 9/6, 2020 at 17:23 Comment(1)
If a PWA is served by an service worker, and the PWA creates an iframe with src in the scope of the service worker, then does the service worker serve the iframe contents too? Does the iframe document have to do anything special to get served by the service worker of its parent?Exieexigency
B
-1

I found all of the existing answers rather confusing (and even somewhat wrong), so I'll try to keep it short:

clients.claim()

This can be used when registering your service worker for the first time.

If you had an existing active service worker, which has just been replaced (either via skipWaiting() or by closing all tabs), then calling clients.claim() has no effect, since all tabs are already being controlled. Only when registering for the first time will the page not be controlled until you call this.

skipWaiting()

This forces the waiting worker to become active and this also claims control over all existing clients. There's no need to call clients.claim() anymore at this point.

If the worker is already active, this does nothing.


One final note, if you call clients.claim() from within a worker that hasn't been activated yet, it will reject. Making this function pretty useless once you have used it for the first time.

Bertolde answered 3/2, 2024 at 18:45 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.