The image below shows that there are two workers installed - one active and the other not active (just installed).
Register a service worker
Make changes to service-worker.js and reload the page.
The logic is that Service Workers check binary diff and updates the versions of the workers.
So a new service worker is spawned with a new version ID. But why does the old one keeps running ? and How do I close it ?
The sw.js is here https://gist.github.com/boopathi/57b7e8b6d657d55bdc7d
By default, until all tabs that have a page controlled by that old service worker are closed/unloaded, the old service worker will stay running. The new service worker will, well, "wait" in the "waiting" state.
There are options that change this default behavior. They're skipWaiting() and clients.claim().
When skipWaiting() is called from an installing service worker, it will, well, skip the "waiting" state and immediately activate. However, it will not necessarily take control of pages despite being activated—that's what clients.claim() will accomplish.
Related
I'm trying to implement a service worker in an application, but I wanted to ensure it's very resilient. I'm making sure the whole application only runs once the service worker is ready, which is generally working fine.
But when something happens during the service worker installation - like the user losing internet connection, it seems like my service worker gets stuck in the trying to install step. Only being installed after a couple of retries. I expect it to be installed as soon as the user reconnects and reloads the first time.
Is my expectation reasonable? Shouldn't the sw just resume installing in the next time the user loads the page?
Notice that this is a very rough prototype.
I have a task router with some workers, when there is an incoming call and the worker does not answer the call, then the worker is been updated, and the status is been set to offline. Can I avoid that and keep the worker in the available activity state?
worker.on 'activity.update', #_onWorkerActivityUpdated
Configuring Default Activities for Worker State Transitions
If a Reservation times out, the Worker is placed in the TimeoutActivity identified by the Workspace. By default this is Offline.
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.
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.
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.
I was reading NekR/offline-plugin source code. In the update method it calls browser's ServiceWorker.update().
I want to know that if this method force activate the new service worker(i.e. skipWaiting) or it just pull the latest service worker and waiting for user to detach service workers from browser(i.e. waiting phase).
No, it does not force the new SW to take control. That could potentially break many applications. Install event is executed and the SW script itself is responsible for calling skipWaiting etc. if it wants to.
You can see that from the spesification of the Service Worker update process. SkipWaiting is not scheduled. https://www.w3.org/TR/service-workers-1/#dom-serviceworkerregistration-update
There's no information regarding the skipping of the waiting phase using ServiceWorkerRegistration.update(), it will only attempts to update the service worker and installs the new worker. You can try to check this documentation just hit the "skip waiting" using developer tool to skip the waiting phase so the new service worker activates.
I know that this already has an answer, but for those that want a straightforward way to bypass the "skip waiting", just add the line below alone in your service-worker.js
self.skipWaiting();
So next time you are updating your service-worker.js, it will "skip waiting".
To immediately activate a service worker after it's installed, I use self.skipWaiting() in the install listener. To immediately take control of a page (without the need for a page navigation, e.g. page load), I use self.clients.claim(). I understand that doing such things means:
Page could first load without it being under the control of a Service Worker, but then be taken over by a Service Worker during its lifespan.
A page could start under the control of version 1 of Service Worker but then be taken over by version 2 during its lifespan.
There are all kinds of warnings online about doing such things, but I don't see the pitfalls. Perhaps one potential problem is if the controlled page does some initial handshake or setup with a Service Worker when it first loads. That obviously will be missed when the new Service Worker activates in the background, but even then, the Service Worker could message its controlling pages to notify them of the change.
It seems to me that for most applications under most scenarios would benefit significantly by using both self.skipWaiting() and self.clients.claim() without any downside. Did I miss something?
The pitfalls of self.skipWaiting() is described really well here (thanks #RobertRowntree for the link):
https://redfin.engineering/how-to-fix-the-refresh-button-when-using-service-workers-a8e27af6df68
As for self.clients.claim(), I still haven't seen a compelling argument against it, but when I do, I'll update my answer.