如何强制服务人员更新?
Posted
技术标签:
【中文标题】如何强制服务人员更新?【英文标题】:How to force service worker to update? 【发布时间】:2017-06-13 16:10:03 【问题描述】:我正在使用 sw-precache 通过 Polymer CLI 构建过程生成我的服务工作,因此它旨在更新已更新文件的哈希以表明需要更新缓存。但是我更新的内容没有在缓存中被替换,所以如果我用 ctrl+r 刷新它会得到一个旧版本,但如果我用 ctrl+shift+r 刷新它就会得到新版本。一个原因可能是我的 Service Worker 没有更新。
This doc 声明
如果 service worker 文件中有一个字节的差异 与现有的相比,它认为它是新的。
,但是如果我的新服务工作者没有更改一个字节怎么办? (如果只有一个哈希发生了变化,就会发生这种情况)。如何配置 sw-precache 以在每个新请求时更新服务工作?
【问题讨论】:
你看过这个吗? developer.mozilla.org/en-US/docs/Web/API/… 并且请确认哈希是否正常工作:这意味着在更改缓存的资产文件后,它会将其反映到服务工作者内容中。换句话说,服务工作者中的哈希值更改。请注意,SW 不关心也无法检查资产文件的内容或版本。唯一可以触发它更新的是它自己的内容。因此,资产文件中的更改应该反映到它们在 SW 中的引用。例如/style.css?hash-of-the-file
我确定哈希值正在改变。我没有测试的“skipWaiting”,我已经阅读了文档,我的理解是这是为了在不重新加载页面的情况下强制更新。我的情况似乎有所不同,因为服务工作者的生命周期结束时,有另一个人在等待并且页面重新加载,而不需要“skipWaiting”。
这根本不是真的。 see the documentation...新版本已在后台安装,但尚未激活。仅当不再加载任何仍在使用旧服务工作者的页面时才会激活它。一旦不再加载此类页面,新的 service worker 就会激活。
嘿,请注意:有一个another question,其中I have just replied。可能也有对您有用的信息,因为它与您的非常相似。
【参考方案1】:
'sw-precache' 已被Workbox 取代,它为您要预缓存的文件生成哈希并将其添加到您的服务工作者的源代码中(我不知道sw-precache
是否以相同的方式工作,杰夫的回答表明确实如此)。如果您要预缓存的任何文件发生变化——并且你重新运行构建——更新后的服务工作者中的哈希值会被更新,这几乎可以保证服务工作者将“至少有一个字节不同”。
当您重新加载 (ctrl-r
) 或重新访问您的应用时,浏览器将再次获取为其注册的 service worker。而且,如果那个 service worker 发生了变化,它将被“排队”来管理应用程序。但它不会开始管理应用程序,直到您在应用程序打开的情况下关闭所有选项卡,然后打开一个新选项卡。
当您硬刷新 (shift-ctrl-r
) it’ll always load without a controller 时,这与使用新的 Service Worker 不同。
为了在开发过程中进行测试,我在 devtools 中使用skip waiting 让新的 Service Worker 替换旧的,而无需等待我关闭所有选项卡。
【讨论】:
【参考方案2】:正如前面的答案所述,浏览器有 1 天(24 小时)的内置限制来查找服务人员的更新,但您需要注意的是您仍然需要致电 .update()
在您的 ServiceWorkerRegistration
对象上,否则将使用文件的原始版本。
在 Chrome 中测试更改时,我总是右键单击刷新按钮并在处理我的 service worker 脚本时选择“空缓存和硬重置”(打开开发人员工具时可用的选项)。
【讨论】:
不错的 Chrome 提示,我永远不会注意到。 在您的开发环境中没问题,但如果您在该内置限制内发布(甚至可能多次)网站更新怎么办? @CsabaToth 我不确定这里的“正确”答案是什么,但您可能只需要等待 24 小时的限制。您确实无法控制客户端的浏览器。上面的答案只是为了在开发过程中提供帮助。请注意,这个答案已经有一年多了,自从我发布之后,条件可能已经改变了。 @jcaruso 你可以显式调用.update()
!但这很丑。【参考方案3】:
如果一个文件的 hash 发生变化,这足以确保 sw-precache
生成的 service worker javascript 文件发生变化。反过来,这足以触发 Service Worker 更新流程。
如果您在测试时没有看到触发更新流,则可能是由于服务工作者 JavaScript 文件使用 HTTP 缓存标头提供,导致它从浏览器的缓存中获取,而不是从网络。
请参阅https://***.com/a/38854905/385997,了解有关 HTTP 缓存标头如何发挥作用的讨论以及与此相关的最佳实践。
【讨论】:
嗯,第一段是我所期望的,但实践表明它并不总是发生。 您的 Service Worker 是否被缓存在某处?如果是这样,那么浏览器将不会知道任何更改。您需要确保任何 Web 缓存都没有缓存您的 Service Worker。【参考方案4】:从用户体验的角度来看,我实现的一个选项是在您的服务工作者上调用 unregister 方法。 (https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/unregister)
注销过程完成后,您可以:
-
强制窗口刷新 (window.location.reload)
根据您的加载过程,您可以获取新的 Service Worker,它有望缓存您的所有新内容。
我之前遇到过关于 service worker 的奇怪问题,所以这种类型的解决方案允许您在一定程度上清除旧缓存并刷新应用程序的状态,而不会强制用户清除他们实际的浏览器缓存,同时重新加载您的应用程序。
EX(如何注销):
serviceworker.unregister()
.then( unregResult =>
//You can check if successful with Promise result 'unregResult'
window.location.reload();
)
【讨论】:
【参考方案5】:在service‑worker.js
中存储一个版本号
控制service-worker.js
中的一个字符更改将自动触发 PWA 更新。因此,如果您将版本号存储在此文件中的const
中并更改它,则会触发 PWA 的更新。
最终如何处理更新由service-worker.js
决定。根据 PWA 资产的规模和波动性,可以定义不同的更新策略。
但是,有一个重要的警告。确保您的资产服务器上的.htaccess
文件设置的浏览器缓存到期指令设置为非常短持续时间(例如hours
)甚至none。
如果不这样做,将导致浏览器在未来几天内看不到 manifest.json
和 service-worker.js
的任何变化。
有关服务工作者行为的更多详细信息,请访问Google Web Fundamentals。
【讨论】:
【参考方案6】: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);
);
【讨论】:
以上是关于如何强制服务人员更新?的主要内容,如果未能解决你的问题,请参考以下文章
带有 DirectRunner 的 Apache Beam (SUBPROCESS_SDK) 仅使用一个工作人员,我如何强制它使用所有可用的工作人员?