skipWaiting()
with StaleWhileRevalidate
the right way
#173
Labels
blog: programming
@post
This is a blog post
tag: pwa
|178273995-9c8a0e84-25ba-4d9a-bc5b-38a7ac3282f5.png
View Post on Blog
It is common to use Workbox
StaleWhileRevalidate
strategy to cache resources which may take some time to fetch. Usually, the resource needs to be updated but not immediately. However, if the resource request takes too much time to complete, the service worker's life cycle and some functionality may be impacted, especiallyself.skipWaiting()
.Why
skipWaiting
is important?By default, a service worker takes over the page from start to end, even if the new service worker is discovered and installed. This behavior ensures consistency. However, if the update is important and does not conflict with the old one, you may want the new one to activate as soon as installed.
Another use case is the click-to-refresh feature. Remember the old service worker is still in charge even though refreshing the page. To update the PWA app without leaving it, skipping the waiting phase of the new service worker is needed. Thus after
location.reload()
, new service worker with new precached assets are there. We will focus on this use case in this post.How to
skipWaiting
withoutStaleWhileRevalidate
strategyAs you may have seen in many documentation and tutorials, it is quite straightforward:
You may need to change the comment line to test skip waiting again.
Complete code for demonstration
Let's add a simple server and some HTML to complete the PWA and simulate a slow request.
The above code might be a little bit long. It does 3 things:
The server is pretty straightforward, using node-static to serve files.
A
favicon.ico
is also needed to avoidfavicon.ico
not found error.Now run
index.js
and:service-worker.js
service-worker.js
, manually reload page and test againYou may found something like this in console:
Then the page reloads, and the button stays disabled because the new service worker is active and no service worker waiting.
Open the Network tab, and you can see
slow.json
is cancelled because of page refresh. Or in Firefox it's directly logged into the console:This is intended because you almost always want to cancel fetching when refreshing the page. But that's where the problem lies when using
StaleWhileRevalidate
strategyStill waiting after
skipWaiting
, whenStaleWhileRevalidate
Now let's add
StaleWhileRevalidate
strategy:open http://localhost:8345/stuck/, repeat the above steps. Here is the example output:
The new service worker is not activated until the request completes. Even if the resource is cached:
Though cached, the
StaleWhileRevalidate
strategy still revalidates the resource in the background. Thus the old service worker is unable to stop until the request finishes.The solution
It's natural to think of aborting the request in the old service worker. Let's add
AbortController
. Notice that you need to let new service worker to skip waiting, and let old service worker to abort fetches. Don't get confused.And the (truncated) output:
The new service worker is immediately activated after aborting the request 🎉
Bonus
If you open multiple tabs at the same time and click the button, all of them are refreshed, avoiding potential conflict between the new service worker and the old page. If this is not the befavior you want, you can always change the condition for the page reload.
The text was updated successfully, but these errors were encountered: