当服务工作者更新时,它不会立即控制页面;而是进入“等待”状态,等待被激活。
令人惊讶的是,在刷新页面后,更新后的服务工作者甚至不会控制标签。Google 解释道:
https://developers.google.com/web/fundamentals/instant-and-offline/service-worker/lifecycle
即使您只在演示中打开一个选项卡,刷新该页面也不足以让新版本接管。这是由于浏览器导航的工作方式。当您进行导航时,当前页面只有在接收到响应标头之后才会消失,即使响应具有
Content-Disposition
标头,当前页面也可能会保留。由于这种重叠,当前服务工作者始终在刷新期间控制客户端。要获取更新,请关闭或导航离开所有使用当前服务工作者的选项卡。然后,当您再次导航到演示时,您应该会看到新内容 [updated content]。
这种模式类似于 Chrome 的更新方式。Chrome 的更新是在后台下载的,但在重新启动 Chrome 之前不会应用。在此期间,您可以继续使用当前版本而不会受到干扰。但是,在开发过程中,这很麻烦,但是 DevTools 有方法使它变得更容易,我将在本文后面介绍。
对于多个选项卡的情况,这种行为是有道理的。我的应用程序是一个需要原子方式更新的捆绑包;我们不能混合和匹配旧的捆绑包和新的捆绑包。 (在本地应用程序中,原子性是自动且保证的。)
但是,在单个选项卡的情况下(我称之为应用程序的“最后打开的选项卡”),此行为并不是我想要的。我希望刷新最后打开的选项卡以更新我的服务工作者。
很难想象有人希望在最后一个打开的标签页刷新时继续运行旧的 service worker。Google 提出的“导航重叠”论点听起来像是不幸 bug 的借口。
我的应用程序通常只在单个标签页中使用。在生产环境中,我希望用户只需通过刷新页面就能使用最新的代码,但这并行不通:旧的 service worker 将在刷新时继续控制页面。
我不想告诉用户,“要接收更新,请务必关闭或导航离开我的应用程序。” 我想告诉他们,“只需刷新”。
如何在用户刷新页面时激活已更新的 service worker?
编辑:我知道有一种快速、简单且错误的解决方法:skipWaiting
在 service worker 的安装事件中使用。 skipWaiting
会使新的 service worker 在更新下载完成后立即生效,而旧的页面标签仍然打开。这会使更新不安全且不可重复;就像在应用程序正在运行时替换本地应用程序包一样。这对我来说是不可接受的。我需要等待用户刷新最后一个打开的标签页。