admin管理员组

文章数量:1323224

When I update the service worker, I close and reopen the page and I get the console log that the new service worker has been installed and activated, and the old cache has been deleted. However, the files listed to be added to the cache are not fetched from the server again, they are stale versions from hours ago. There's no way to make it update the files short of clearing storage in the Chrome dev tools.

How can I make my service worker populate it's cache with fresh files when a new version is installed?

For example, "stylesheet.css" is still an old version when the service worker updates:

let cacheName = "abc_web_v1_15";

self.addEventListener('install', (event) => {
    console.log('[Service Worker] Install');
    event.waitUntil(
        caches.open(cacheName).then(function (cache) {
            return cache.addAll([
                "/".
                "/stylesheet.css",
                ...
            ]);
        })
    );
});
self.addEventListener('fetch', (e) => {
    e.respondWith(
        caches.match(e.request).then(function (r) {
            console.log('[Service Worker] Fetching resource: ' + cacheName + ' ' + e.request.url);
            if (r) {
                console.log(cacheName + ' returning cached  ' + e.request);
                return r;
            } else {
                console.log(cacheName + ' returning fetched  ' + e.request);
                return fetch(e.request);
            }
        })
    )
});

self.addEventListener('activate', (e) => {
    console.log('[Service Worker] Activate');
    e.waitUntil(
        caches.keys().then((keyList) => {
            return Promise.all(keyList.map((key) => {
                if (cacheName.indexOf(key) === -1) {
                    console.log(`[Service Worker] Removing Cached Files from Cach-${key}`);
                    return caches.delete(key);
                }
            }));
        })
    );
});

When I update the service worker, I close and reopen the page and I get the console log that the new service worker has been installed and activated, and the old cache has been deleted. However, the files listed to be added to the cache are not fetched from the server again, they are stale versions from hours ago. There's no way to make it update the files short of clearing storage in the Chrome dev tools.

How can I make my service worker populate it's cache with fresh files when a new version is installed?

For example, "stylesheet.css" is still an old version when the service worker updates:

let cacheName = "abc_web_v1_15";

self.addEventListener('install', (event) => {
    console.log('[Service Worker] Install');
    event.waitUntil(
        caches.open(cacheName).then(function (cache) {
            return cache.addAll([
                "/".
                "/stylesheet.css",
                ...
            ]);
        })
    );
});
self.addEventListener('fetch', (e) => {
    e.respondWith(
        caches.match(e.request).then(function (r) {
            console.log('[Service Worker] Fetching resource: ' + cacheName + ' ' + e.request.url);
            if (r) {
                console.log(cacheName + ' returning cached  ' + e.request);
                return r;
            } else {
                console.log(cacheName + ' returning fetched  ' + e.request);
                return fetch(e.request);
            }
        })
    )
});

self.addEventListener('activate', (e) => {
    console.log('[Service Worker] Activate');
    e.waitUntil(
        caches.keys().then((keyList) => {
            return Promise.all(keyList.map((key) => {
                if (cacheName.indexOf(key) === -1) {
                    console.log(`[Service Worker] Removing Cached Files from Cach-${key}`);
                    return caches.delete(key);
                }
            }));
        })
    );
});
Share Improve this question edited Jan 13, 2020 at 22:46 Steve M asked Jan 13, 2020 at 22:41 Steve MSteve M 9,79412 gold badges53 silver badges105 bronze badges 2
  • I answered a similar issue here, I hope it will help you: stackoverflow./a/64880568/7626299 – adrienv1520 Commented Nov 17, 2020 at 17:57
  • I answered a similar issue here, I hope it will help you: stackoverflow./a/64880568/7626299 – adrienv1520 Commented Nov 17, 2020 at 17:58
Add a ment  | 

3 Answers 3

Reset to default 5

The problem is very simple: when your Service Worker requests the "new" files, that fetch request goes through the regular browser HTTP cache. If the resource is found there, browser automatically returns that and doesn't go to network.

If you look at this snippet from your code:

return cache.addAll([
                "/".
                "/stylesheet.css",
                ...
            ]);

you'll see that your stylesheet's name is always the same no matter the content. In other words, when your stylesheet updates, the filename is still the same. For this reason the file is already in the browser's HTTP cache and thus SW gets it when it asks for it.

You should version your files. Usually hash of the file contents is used. With hash naming you end up with names like stylesheet.iudfirio132.css and that name changes every time the file changes even one character. This way new version of your application always uses resources with different names. You should also have build tooling like Workbox precaching to update the resource list in your Service Worker file so that you don't need to do it manually. More: https://developers.google./web/tools/workbox/modules/workbox-precaching

To pletely grasp the subject here I remend you to read this blog post, "Caching best practices & max-age gotchas" https://jakearchibald./2016/caching-best-practices/

I keep this self-destructing Service Worker handy for when I need to clear out all old Service Workers and Service Worker caches.

I find it a really useful tool.

self.addEventListener('install', event => self.skipWaiting());

self.addEventListener('activate', event => {

  // Delete all Service Worker Caches
  caches.keys().then(cacheNames => {for (let name of cacheNames) {caches.delete(name);}});

  // Unregister all Service Workers
  self.registration.unregister()

    .then(() => self.clients.matchAll())

    .then((clients) => clients.forEach(client => client.navigate(client.url)))

});

Further Reading:

  • https://medium./@nekrtemplar/self-destroying-serviceworker-73d62921d717
  • https://github./NekR/self-destroying-sw/blob/master/tests/service-worker/www_fixed/sw.js

I answered a similar issue here: https://stackoverflow./a/64880568/7626299

As pate mentioned, even though you're updating your service worker with new code, a new cache name, calling self.skipWaiting(), he's still putting in cache the old resources in cache!

Actually you can rewrite your install event handler and get rid of cache.addAll. To solve this issue you need to fetch each resource by setting the cache option to reload so the browser will use the network to get the resource and not the cache.

const req = new Request(url, { cache: 'reload' });

More details here.

本文标签: javascriptService Worker updatesbut old file is still cachedStack Overflow