Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I clear service worker caches when unregistering?

Popular question How do I uninstall a Service Worker? has a fine answer for unregistering a service worker using JavaScript. How can I get the service worker to clear any named caches when it unregisters?

From MDN unregister, The service worker will finish any ongoing operations before it is unregistered. So, it sounds like it should be possible to listen for an uninstall event, but no such event exists as far as I can tell. For giggles, I tried adding self.addEventListener('uninstall', ...) to the service worker, but as expected, it did not fire on unregister. I also tried listening for any message that might be sent on unregister... no dice.

I also considered watching the service worker state, but none of installing, installed, activating, activated, and redundant appear relevant. Not to mention, it doesn't look like message passing to the service worker is possible, so I'm not sure what I'd do with an uninstalling state from outside the service worker anyways.

Reaching for straws, while I see references to an uninstalling flag, I haven't seen it exposed anywhere. Suggestions?

like image 267
MDMower Avatar asked Aug 31 '25 03:08

MDMower


2 Answers

The following code should unregister all service workers and clear out everything in the Cache Storage API for your origin:

async function unregisterAndClearCaches() {
  const registrations = await navigator.serviceWorker.getRegistrations();
  const unregisterPromises = registrations.map(registration => registration.unregister());

  const allCaches = await caches.keys();
  const cacheDeletionPromises = allCaches.map(cache => caches.delete(cache));

  await Promise.all([...unregisterPromises, ...cacheDeletionPromises]);
}

Using the Clear-Site-Data header is another option for "forcing" everything to be cleared (service worker registration, caches, etc.) in a single action.

like image 183
Jeff Posnick Avatar answered Sep 02 '25 15:09

Jeff Posnick


This can be accomplished with message passing. One reason I prefer this to the answer by Jeff Posnick is that the name of the cache does not need to be known outside of the service worker. In the service worker, add a message listener:

self.addEventListener('message', (event) => {
    messageHandler(event);
});

The messageHandler() can then take action on various passed messages. For example:

function messageHandler(event) {
    if (event.data === 'purge_cache') {
        caches.delete('mycache')
        .then((success) => {
            console.log("Cache removal status: " + success);
        })
        .catch((err) => {
            console.log("Cache removal error: ", err);
        });
    }
}

To trigger this action, post the message from your script on a page that is under the service worker's scope. So, for the original question of how to delete the cache and then unregister the service worker, you could do this:

navigator.serviceWorker.getRegistration()
.then((registration) => {
    registration.active.postMessage('purge_cache');
    registration.unregister()
    .then((success) => {
        console.log('Service worker unregistration status: ' + success);
    })
    .catch((err) => {
        console.log('Service worker unregistration failed', err);
    });
})
.catch((err) => {
    console.log('Service worker registration not found.');
});

Notice, I did not wait for a successful reply from postMessage('purge_cache'); from MDN unregister, "The service worker will finish any ongoing operations before it is unregistered."

like image 38
MDMower Avatar answered Sep 02 '25 16:09

MDMower