What is the use of `self.Clients.claim()`
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.
- Installing; This is the first phase after registration. When the
oninstall
handler completes, the service worker is considered installed. - Installed; The service worker is waiting for clients using other service workers to be closed.
- Activating; There are no clients controlled by other service workers. When the
onactive
handler completes, the service worker is considered activated. - 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.
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 andclients.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.
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.