Workbox: the danger of self.skipWaiting()
Asked Answered
A

1

14

I use Workbox to pre-cache assets required to render the app shell, including a basic version of index.html. Workbox assumes that index.html is available in cache, otherwise, page navigation fails because I have this registered in my Service Worker:

workbox.routing.registerNavigationRoute('/index.html');

I also have the self.skipWaiting() instruction in the install listener:

self.addEventListener('install', e => {
  self.skipWaiting();
});

As I understand it, there are 2 install listeners now:

  • One that's registered by Workbox for pre-caching assets (including index.html)
  • One that I registered manually in my Service Worker

Is it possible for self.skipWaiting() to succeed while Workbox's install listener fails? This would lead to a problematic state where assets don't get pre-cached but the Service Worker is activated. Is such a scenario possible and should I protect against it?

Aspirator answered 26/3, 2018 at 1:15 Comment(1)
Not sure. But: I think you could test this out yourself. From Chrome DevTools block network request to one of the assets pre-caching is trying to cache and see what happens.Maravedi
B
38

I highly recommend "The Service Worker Lifecycle" as an authoritative source of information about the different stages of a service worker's installation and updating.

To summarize some info from that article, as it applies to your question:

  • The service worker first enters the installing phase, and however many install listeners you've registered, they will all get a chance to execute. As you suggest, Workbox creates its own install listener to handle precaching.

  • Only if every install listener completes without error will the service worker move on to the next stage, which might either be waiting (if there is already an open client using the previous version of the service worker) or activating (if there are no clients using the previous version of the service worker).

  • skipWaiting(), if you choose to use it, it will bypass the waiting stage regardless of whether or not there are any open clients using the previous version of the service worker.

  • Calling skipWaiting() will not accomplish anything if any of the install listeners failed, because the service worker will never leave the installing phase. It's basically a no-op.

The one thing that you should be careful about is using skipWaiting() when you are also using lazy-loading of versioned, precached assets. As the article warns:

Caution: skipWaiting() means that your new service worker is likely controlling pages that were loaded with an older version. This means some of your page's fetches will have been handled by your old service worker, but your new service worker will be handling subsequent fetches. If this might break things, don't use skipWaiting().

Because lazy-loading precached, versioned assets is a much more common thing to do in 2018, Workbox does not call skipWaiting() for you by default. It's up to you to opt-in to using it.

Bromide answered 26/3, 2018 at 14:40 Comment(2)
Excellent! Your comment: Only if every install listener completes without error will the service worker move on to the next stage is really helpful. I didn't see it in The Service Worker Lifecycle article, so hopefully your answer helps others as well.Aspirator
It's kind of the same ground as what's covered in developers.google.com/web/fundamentals/primers/service-workers/…: The install event is the first event a service worker gets, and it only happens once. A promise passed to installEvent.waitUntil() signals the duration and success or failure of your install. A service worker won't receive events like fetch and push until it successfully finishes installing and becomes "active".Bromide

© 2022 - 2024 — McMap. All rights reserved.