如何强制更新Service Worker?

28
我正在使用sw-precache来生成我的服务工作,与Polymer CLI构建过程一起使用,因此旨在更新更新文件的哈希,以表示需要更新缓存。但是我的更新内容没有在缓存中被替换,因此如果我使用ctrl + r刷新,则会获得旧版本,但如果我使用ctrl + shift + r刷新,则会获得新版本。导致这种情况的原因可能是我的服务工作者没有被更新。 此文档指出:

即使服务工作者文件与其当前文件相比只有一个字节的差异,它也将被视为新文件。

但是,如果我的新服务工作者没有更改一个字节怎么办?(如果只更改了一个哈希值,则会发生这种情况)。如何配置sw-precache在每个新请求时更新服务工作?

1
你看过这个吗?https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting请确认哈希值是否正常工作:即更改缓存的资产文件后,它会反映到服务工作者内容中。换句话说,哈希值在服务工作者中会发生变化。请注意,SW不关心也无法检查资产文件的内容或版本。唯一可以触发更新的是它自己的内容。因此,资产文件的更改应该反映在它们在SW中的引用中。例如 /style.css?{hash-of-the-file} - Umur Karagöz
我确信哈希值正在改变。我没有测试“skipWaiting”,但我已经阅读了文档并理解了这是为了在不重新加载页面的情况下强制更新。我的情况似乎不同,因为服务工作者的生命周期在有另一个等待的服务工作者并且页面重新加载时就会结束,而不需要使用“skipWaiting”。 - Jp_
1
这完全不是事实。请参阅文档新版本会在后台安装,但尚未激活。只有当没有仍在使用旧服务工作者的页面加载时,它才会被激活。一旦没有更多这样的页面加载,新的服务工作者就会被激活。 - Umur Karagöz
嘿,提醒一下:有一个另一个问题,我刚回答了它(链接)。因为这个问题非常相似,所以对你也可能有用的信息。 - Umur Karagöz
6个回答

21

正如之前的回答所述,浏览器默认有一天(24小时)的时间限制来查找服务工作者更新,但需要注意的是,在原始版本文件被使用之前,您仍然需要调用.update()在您的ServiceWorkerRegistration对象上。

在Chrome中测试更改时,我总是右键单击刷新按钮并选择“清空缓存并强制重置”(选项在开发者工具打开时可用),以便在我的服务工作者脚本上工作。


12
不错的Chrome提示,我从未注意过。 - Jp_
在您的开发环境中这没问题,但如果您在内置限制期间发布(甚至可能是多个)更新到您的网站上呢? - Csaba Toth
@CsabaToth 我不确定这里的“正确”答案是什么,但你可能需要等待24小时限制。你真的无法控制客户端浏览器。上面的答案只是为了在开发过程中提供帮助。请注意,这个答案已经超过一年了,自我发布以来情况可能已经改变。 - jcaruso
@jcaruso 你可以显式地调用 .update()!但那很丑。 - Csaba Toth

14

'sw-precache'已被Workbox取代,它为您想要预缓存的文件生成哈希,并将其添加到服务工作者的源代码中(我不知道sw-precache是否以同样的方式工作,Jeff的答案表明这确实是这种情况)。如果您想要预缓存的任何文件发生更改,并且重新运行构建,则服务工作者中更新的哈希将更新,这基本上保证了服务工作者至少会“有一个字节的不同”。

当您重新加载(ctrl-r)或重新访问您的应用程序时,浏览器会再次获取为其注册的服务工作者。并且,如果该服务工作者已更改,它将被“排队”以管理该应用程序。但是,在关闭所有打开该应用程序的选项卡后,它不会开始管理该应用程序,直到您打开一个新选项卡。

当您进行硬刷新(shift-ctrl-r它将始终不使用控制器加载,这与使用新的服务工作者不同。

在开发过程中进行测试时,我使用跳过等待在devtools中,以使新的服务工作者取代旧的服务工作者,而不必等待我关闭所有选项卡。


11

如果一个文件的哈希值改变了,就足以确保由sw-precache生成的服务工作者JavaScript文件发生了变化。这反过来又足以触发服务工作者的更新流程。

如果在测试过程中未触发更新流程,则可能是由于服务工作者JavaScript文件使用HTTP缓存标头进行了服务,导致它从浏览器缓存而不是网络获取。

请参见https://dev59.com/kFkT5IYBdhLWcg3wRNYR#38854905,了解HTTP缓存标头的作用及相关最佳实践。


2
好的,第一段是我期望的,但实践表明这并不总是发生。 - Csaba Toth
你的服务工作者是否被缓存到某个地方了?如果是这样,那么浏览器就不会知道任何变化。你需要确保任何网络缓存都没有缓存你的服务工作者。 - Max Waterman

4

从用户体验的角度来看,我实施的一个选项是在您的服务工作者中调用“取消注册”方法。 (https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/unregister)

完成注销过程后,您可以:

  1. 强制窗口刷新 (window.location.reload)
  2. 根据您的加载过程,您可以获取新的服务工作者,希望它能缓存您的所有新内容。

我以前遇到服务工作者的奇怪问题,因此这种解决方案允许您在不强制用户清除其实际浏览器缓存的情况下,清除旧缓存并刷新应用程序状态,同时重新加载应用程序。

示例 (如何取消注册):

serviceworker.unregister()
    .then( unregResult => { 
       //You can check if successful with Promise result 'unregResult'
       window.location.reload();
    })

2

service-worker.js中存储版本号

控制service-worker.js中的一个字符更改将自动触发PWA更新。因此,如果您将版本号存储在此文件中的const中并进行更改,则会触发PWA的更新。

如何处理更新最终由service-worker.js确定。可以根据PWA资产的大小和波动性定义不同的更新策略。

然而,有一个重要的警告。请确保由您的资产服务器上的.htaccess 文件设置的浏览器缓存到期指令设置为非常短的持续时间(例如小时)甚至为none。 未能这样做将导致浏览器在接下来的几天内看不到manifest.jsonservice-worker.js中的任何更改。

有关服务工作者行为的更多详细信息可以从Google Web Fundamentals获取。


-4
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {

    //Force the Service Worker to Upddate
    self.registration.update();

    const notification = JSON.parse(payload.data.notification);
    return self.registration.showNotification(notification.title, notification);

});

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