In my web app, some web requests must be intercepted and modified by the service worker, otherwise the requests will fail. This is especially important on the very first visit for a new user. I use clientsClaim()
to ensure that.
Since I need to make sure the service worker is ready before I make the request, I tried to wait for navigator.serviceWorker.ready
:
await navigator.serviceWorker.ready;
fetch(myRequest);
However, I found it doesn't work as intended. The very first request on the first visit is not intercepted. So I tried to add some wait time:
await navigator.serviceWorker.ready;
await twoSeconds();
fetch(myRequest);
This works, but it damages user experience because it delays the first meaningful UI. On the other hand, I also can't be sure 2 seconds is long enough for every computer.
What's the event that can tell me as soon as the the sw is ready to intercept traffic? It's only a problem on the first visit, but ideally the event will fire on every reload, because the code is easier to write if I simply await the same thing on every visit.
I think you're looking for a promise that you can use to signal when the current page is under control of a service worker.
This can be achieved via
await new Promise(r => {
if (navigator.serviceWorker.controller) return r();
navigator.serviceWorker.addEventListener('controllerchange', e => r());
});
// At this point, the page will be controlled by a service worker.
This code is adapted from this GitHub discussion, and there's more context there.
Generally speaking, it's not great to design a page that will only work if it's controlled by a service worker, since service workers are intended to be progressive enhancement, rather than a core requirement. But if you have that use case, the code above will help.