Skip to content
Advertisement

How to ensure that `self.skipWaiting()` works while allowing POST requests in service worker’s fetch event

I’ve noticed that my service worker doesn’t respond to self.skipWaiting() when there are still tasks to be run.

In my service worker’s fetch event, I see various Firebase polls that use HTTP POST requests.

If I handle these requests in the service worker like so:

self.addEventListener("fetch", (event) => {
  if (event.request.method === "POST") {
    return event.respondWith(new Response(null, {status: 444}))
  }

  ...
})

Then self.skipWaiting() always works as expected.

However, if I do the following:

self.addEventListener("fetch", (event) => {
  if (event.request.method === "POST") {
    return event.respondWith(fetch(event.request))
  }

  ...
})

Then self.skipWaiting() seems to have no effect. In Chrome’s devtools, the new service worker still isn’t active (and also clicking on the blue skipWaiting link also has no effect). Chrome devtools screenshot showing the new service worker as waiting to activate

As a result, it seems that I have to choose between ensuring that self.skipWaiting() works, and allowing Firebase’s polling requests, but not both. Is there a way get self.skipWaiting() to work while still allowing Firebase’s polling requests?

Advertisement

Answer

I don’t see from your code where you’re calling self.skipWaiting(), but the main thing to know about that function is that it “flips” a flag and attempts to activate the waiting service worker. I’m not sure which part of that sequence is not working as expected, and I’m also not sure if you’re describing something that happens just in Chrome or in other browsers as well. If you’re seeing unexpected behavior just in Chrome, filing a bug is probably your best bet.

That being said, in the interest of providing a workaround, I wanted to say that you don’t have to call event.respondWith() inside of a fetch event handler at all. If all your fetch handlers complete without any of them calling fetchEvent.respondWith(), then the default browser networking behavior will be used instead. So you could restructure your fetch handler like the following, and perhaps work around the issue.

self.addEventListener("fetch", (event) => {
  if (event.request.method === 'POST') {
    return;
  }

  // Your non-POST response logic goes here.
});
Advertisement