如何清除Service Worker的缓存?

82

我有一个带有Service Worker 的HTML页面,它会缓存我的index.html和JS文件。

问题是当我更改JS文件时,更改不会直接在客户端浏览器中显示。当然,在Chrome开发工具中,我可以禁用缓存。但在Chrome移动版中,我该怎么做呢?

我尝试访问站点设置并点击CLEAR&RESET按钮。但它仍会加载旧页面/从缓存中加载。我尝试使用其他浏览器或Chrome的隐身模式,它会加载新页面。

然后,我尝试清除浏览数据(仅缓存),这时它就有效了。

我想这应该不是正确的操作方式吧?如果不清除Chrome浏览器缓存,用户将无法得知页面是否已更新。


非常感谢Hashbrown。我使用这种方式来更新我的应用程序,并使用我在此页面中解释的自定义检查系统:https://dev59.com/x7Xna4cB1Zd3GeqPDgNv#56984209 - Abbas Habibnejad
6个回答

123

如果您知道缓存名称,可以在工作者中的任何位置简单调用caches.delete()

caches.delete(/*name*/);

如果你想要清除所有缓存(而且不想等待它们,比如说这是一个后台任务),你只需要添加此内容

caches.keys().then(function(names) {
    for (let name of names)
        caches.delete(name);
});

2
谢谢您。这个简单明了得多。我只是快速地写了我的答案来回答问题。 - elf
2
没关系。如果有人想在“activate”监听器中删除特定的缓存集,你的代码就很完美了;我只是为了让某些人只清除一个/所有缓存而已。 - Hashbrown
4
最紧凑的代码可能是:caches.keys().then(cs=>cs.forEach(c=>caches.delete(c))),对于异步函数可以使用(await caches.keys()).forEach(c=>caches.delete(c)) - Pat Mächler
在我所在的地方,您先生会被视为“大胡子”!(这是一种恭维) - Khaledonia
1
注意!你应该检查 caches 是否存在。如果你想在 Service Worker 之外清除缓存,请添加类似于 if (!window.caches) return; 的代码。另外要注意,在 HTTP 环境下(如 Chrome)可能不存在 caches 对象。 - Nux
@Hashbrown - 有没有办法使用Workbox的GenerateSW()来实现这个目标?对于我的需求,每次发布新的Service Worker时重置所有缓存将是理想的。 - Adam Youngers

45

使用此功能删除过期缓存:

self.addEventListener('activate', function(event) {
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.filter(function(cacheName) {
          // Return true if you want to remove this cache,
          // but remember that caches are shared across
          // the whole origin
        }).map(function(cacheName) {
          return caches.delete(cacheName);
        })
      );
    })
  );
});

7
这里的“self”是指窗口对象(window object)还是service worker? - loopmode
63
在 Stack Overflow 上,为了让你的解决方案更加可信,最好附上一个说明它为什么有效的解释。如果需要更多信息,请阅读《如何回答》(//stackoverflow.com/help/how-to-answer)。 - Samuel Liew
3
self 表示 serviceWorker 实例。 :) - Sunjoong Kevin Kim
3
self 是一个 "SharedWorkerGlobalScope" 对象。 - renardesque
1
使用'this'代替'self'可以达到相同的效果。但是这两个关键字之间有所不同。 - Evading Shadows
显示剩余2条评论

16

通常您需要在服务工作者的JS文件中更新CACHE_NAME,以便您的工作者被重新安装:

self.addEventListener('install', evt => {
  evt.waitUntil(
    caches.open(CACHE_NAME).then(cache => cache.addAll(inputs))
  )
})

或者,要清除PWA的缓存,请查找缓存名称:

self.caches.keys().then(keys => { keys.forEach(key => console.log(key)) })
然后运行以下命令来删除它:
self.caches.delete('my-site-cache')

然后刷新页面。

如果你在刷新后的控制台中看到任何与工作人员相关的错误,你可能还需要取消注册已注册的工作人员:

navigator.serviceWorker.getRegistrations()
  .then(registrations => {
    registrations.forEach(registration => {
      registration.unregister()
    }) 
  })

1
最后的代码:"navigator.serviceWorker......"帮助我在删除superpwa WordPress插件后,删除与服务工作者相关的所有缓存。谢谢。 - Vitalij
1
你的代码块2和3上面的描述性词语是否颠倒了? - David
1
谢谢,David。在你的帮助下已经解决了。 - vhs
是的!仅仅删除服务工作者还不够,您还必须注销它!耶! - Phillip Senn

9

使用async/await最优雅的解决方案:

const cacheName = 'v2';

self.addEventListener('activate', event => {
// Remove old caches
  event.waitUntil(
    (async () => {
      const keys = await caches.keys();
      return keys.map(async (cache) => {
        if(cache !== cacheName) {
          console.log('Service Worker: Removing old cache: '+cache);
          return await caches.delete(cache);
        }
      })
    })()
  )
})

服务工作者已安装在您的浏览器中。如果在线,您的浏览器将每次请求您的远程工作者并更新其本地安装版本以供离线使用。您可以通过在“获取”事件中的cache.put()之后在控制台中打印它来查看哪些文件被缓存,例如console.log('Caching:', event.request.url)。 - Esteban Ortega

2

这是唯一对我有效的代码。这是Mozilla文档的改编:

//Delete all caches and keep only one
const cachNameToKeep = 'myCache';

//Deletion should only occur at the activate event
self.addEventListener('activate', event => {
    var cacheKeeplist = [cacheName];
    event.waitUntil(
        caches.keys().then( keyList => {
            return Promise.all(keyList.map( key => {
                if (cacheKeeplist.indexOf(key) === -1) {
                    return caches.delete(key);
                }
            }));
        })
.then(self.clients.claim())); //this line is important in some contexts
});

4
cacheNameToKeep ?? [cacheName] ?? 这两个是同一个东西吗?self.clients.claim() 是什么作用? - zipzit
激活后,服务工作者将控制页面,但仅限于在register()成功之后打开的页面。换句话说,必须重新加载文档才能实际进行控制,因为文档在其生命周期内始终存在或不存在服务工作者。为了覆盖这种默认行为并接管打开的页面,服务工作者可以调用self.clients.claim() - Emeka Augustine

0

我曾经感到非常绝望,直到我决定直接在开发工具中更改代码。
这可能不会清除缓存并替换文件,但至少它可以让你调试代码,直到找到完美的方法为止。
另一个需要注意的是,完全关闭浏览器并重新打开页面可能有所帮助,但这仍然是一种不好的调试实践!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接