What is the use of `self.Clients.claim()`
Asked Answered
D

4

30

To register a service worker, I can call

navigator.serviceWorker.register('/worker.js')

Every time the page loads it checks for an updated version of worker.js. If an update is found, the new worker won't be used until all the page's tabs are closed and then re-opened. The solution I read was:

self.addEventListener('install', function(event) {
  event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', function(event) {
  event.waitUntil(self.clients.claim());
});

I can understand the skipWaiting part, but what exactly does clients.claim() do? I've done some simple tests and it seems to work as expected even without it.

Dustheap answered 7/12, 2016 at 3:58 Comment(2)
Quick comment: calling registration.update() isn't required to check for an updated service worker script. That's already done automatically by the browser after a navigation request. registration.update() allows you to for a check without having to wait for navigation requests, and it's usually not necessary.Discussant
Yes, I just found that out since I wrote the question.Dustheap
D
19

I'm excerpting the following from a guide to the service worker lifecycle:

clients.claim

You can take control of uncontrolled clients by calling clients.claim() within your service worker once it's activated.

Here's a variation of the demo above which calls clients.claim() in its activate event. You should see a cat the first time. I say "should", because this is timing sensitive. You'll only see a cat if the service worker activates and clients.claim() takes effect before the image tries to load.

If you use your service worker to load pages differently than they'd load via the network, clients.claim() can be troublesome, as your service worker ends up controlling some clients that loaded without it.

Note: 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.

Discussant answered 9/12, 2016 at 17:51 Comment(1)
So I take it that self.skipWaiting() would be used to immediately apply an update to an existing serviceWorker, and clients.claim() would be used for taking control immediately on the first load.Dustheap
C
22

I had trouble wrapping my head around clients.claim as well and none of the explanations made any sense to me so hopefully this answer helps anyone struggling as well.

To understand Clients.claim we have to look at the worker lifecycle.

  1. Installing; This is the first phase after registration. When the oninstall handler completes, the service worker is considered installed.
  2. Installed; The service worker is waiting for clients using other service workers to be closed.
  3. Activating; There are no clients controlled by other service workers. When the onactive handler completes, the service worker is considered activated.
  4. Activated; The service worker now controls the page.

skipWaiting and Clients.claim are designed to solve different problems.

Clients.claim ONLY has an effect on the very first time your webpage goes from an uncontrolled webpage to a controlled (by a service worker) webpage by registering a service worker.

skipWaiting is exactly what it says. It skips the waiting phase and moves directly to activating. Once activated it is now the active service worker for all clients. Clients being any window or tab that has a webpage open that is within the scope of your service worker.


So why do we need Clients.claim then?

This confused me and I bet it confused you too. The answer is best described in an example.

Imagine your webpage DOES NOT register a service worker and is therefor uncontrolled. You have two tabs (clients) of your webpage open. You make an update to your webpage so that it will now register a service worker.

You decide to reload the first tab (client), it will now fetch the script that registers the service worker and it will start to install. Once installed it notices that no other client is being controlled by a service worker so it does not have to wait and it can immediately safely activate the service worker and any fetch of a resource will now go through your service worker.

However, here is the catch, your other tab (client) will also have an active service worker now, BUT, it is not yet being controlled. Meaning any fetch will not go through the service worker yet. You need to reload any other tab (client) in order for it to be controlled by the active service worker. This is confusing, since if any new service worker hereafter becomes active by forcing it with skipWaiting, the other tabs (clients) will immediately be controlled by the new active service worker. So I emphasize the reload part is needed ONLY when an uncontrolled webpage becomes controlled.

Enter Clients.claim. When you call self.clients.claim() in the first service worker when it becomes activated, like so:

self.addEventListener('activate', event => {
  event.waitUntil(clients.claim());
});

It will make sure the other tabs (clients) that were uncontrolled, but have an active service worker, will get controlled by the active service worker. Meaning any fetch to a resource will now go through the active service worker. Without Clients.claim the service worker is not used until the page is reloaded.

Again, if all the webpages are being controlled by a service worker already. If a NEW service worker is detected and installed, it normally waits until all tabs with the webpage (clients) are closed. The next time you visit the webpage it will have activated the new service worker and the webpage is being controlled by it.

However, if you don't close all the clients and you force the new service worker by using skipWaiting it will immediately become active for all clients and also controlled. Meaning any new fetch for a resource from ANY of the clients will now immediately go through your new service worker. Now you don't need to use Clients.claim in order for the other clients to start using your new service worker.

This was my attempt, hopefully it helped someone.

Crayfish answered 25/5, 2022 at 11:37 Comment(3)
It does help me. But as explained then should we avoid using skipWaiting and clients.claim? Letting new service worker controls old pages will likely cause troubles, isn't it?Renowned
It really depends on the situation and what your code is doing. In most cases it will not cause for any trouble, that's why they exist in the first place and are most commonly used. However only you as a developer can understand the implications when you push a (new) service worker. An old database structure for example.Crayfish
I think there is a small mistake, when reload the first tab and register service worker first time, after become active, you need to reload the tab again then any fetch of a resource will now go through your service worker just like other tabs you mentionedSarcenet
D
19

I'm excerpting the following from a guide to the service worker lifecycle:

clients.claim

You can take control of uncontrolled clients by calling clients.claim() within your service worker once it's activated.

Here's a variation of the demo above which calls clients.claim() in its activate event. You should see a cat the first time. I say "should", because this is timing sensitive. You'll only see a cat if the service worker activates and clients.claim() takes effect before the image tries to load.

If you use your service worker to load pages differently than they'd load via the network, clients.claim() can be troublesome, as your service worker ends up controlling some clients that loaded without it.

Note: 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.

Discussant answered 9/12, 2016 at 17:51 Comment(1)
So I take it that self.skipWaiting() would be used to immediately apply an update to an existing serviceWorker, and clients.claim() would be used for taking control immediately on the first load.Dustheap
F
12

Service worker takes controls from the next page-reload after its registration. By using self.skipWaiting() and self.clients.claim(), you can ask the client to take control over service worker on the first load itself.

e.g

Let's say I cache a files hello.txt, and again If I make a call for hello.txt it will have make server call even though I have resource in my cache. This is the scenario when I don't use self.clients.claim(). However on making a server call for hello.txt on next page reloads, it will be serving the resource from the cache.

To tackle this problem, I have to use combination of self.skipWaiting() and self.clients.claim() so that service worker starts serving content as soon as it is activated.

P.S:

next page-reload means page revisit.

first load signifies the moment when page is visited for the first time.

Filagree answered 19/6, 2017 at 9:15 Comment(7)
so using self.clients.claim will call the server for the file even that file is in the cache? Is that right? can you please mention clearly what it means by next page reload or first load?Zinnia
Using self.clients.claim will not call the server if file is in that cache. It will be served from the cache. Edited post as per your suggestion regarding next page reload and first loadFilagree
Thank you for the modification but still, it's not clear to me that for which scenario you will use self.clients.claim() and for which you will not write this method? > If I want to get file content always from the server then do I need to write self.clients.claim() and later it will fetch from the cache.Zinnia
In that case, you don't needFilagree
but what if I require one file always get from the server and others files can be fetched from cache ( if exist), because we write this self.client.claims in activate event listener and that can be configured only with one setting.either write it or not.Zinnia
You can always configure the list of assets you want to cache. For others service worker will automatically bypass the request to server.Filagree
Thank you very much. will you please see my issue mentioned hereZinnia
C
3

Clients.claim() makes the service worker take control of the page when you first register a service worker. If there is already a service worker on the page, it will make no difference. skipWaiting() makes a new service worker replace an old one. Without it, you would have to close the page (and any other open tabs containing a page in the same scope) before the new service worker was activated.

Chris answered 10/6, 2020 at 11:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.