【问题标题】:What are the downsides to using skipWaiting and clientsClaim with Workbox?将 skipWaiting 和 clientsClaim 与 Workbox 一起使用有什么缺点?
【发布时间】:2018-08-06 20:23:27
【问题描述】:

默认情况下,skipWaiting 在 Workbox 中设置为 false。假设您使用 Workbox 创建的 Service Worker 进行缓存,将其设置为 true 有什么缺点吗?如果不这样做,您的应用程序的下一个构建将发布更新的资源 url(来自 webpack)。这些 url 将在 service worker 的预缓存清单中更新,但如果没有 skipWaiting,更新后的 service worker 将不会被激活以利用它们,直到用户关闭浏览器并重新打开。

这些更新的资源正确加载(webpack 将加载包含新哈希值的资源),但它们永远不会被缓存,直到用户再次关闭所有打开的正在运行的浏览器服务人员,然后重新打开。在这种情况下,是否有理由不将skipWaiting 设置为true?

作为一个相关问题,clientsClaim 控制究竟什么?只需打开 skipWaiting 即可解决上述问题;那么clientsClaim是做什么的呢?

【问题讨论】:

    标签: service-worker workbox


    【解决方案1】:

    作为背景,我建议阅读“The Service Worker Lifecycle”。它是从通用 Service Worker 的角度编写的,但这些要点也适用于 Workbox 支持的 Service Worker。

    在这个“Paying Attention while Loading Lazily”谈话和微站中,也从使用create-react-app的角度更详细地解释了这些概念。

    Workbox 的实现

    Workbox 使用 install 事件处理程序在预缓存清单中缓存新的或更新的条目(在需要时将 __WB_REVISION__ 查询参数附加到条目的 URL,以避免用不同的修订覆盖现有条目),它使用activate 事件处理程序,用于删除以前缓存的条目,这些条目不再列在预缓存清单中。

    如果skipWaiting 为真,则activate 处理程序负责从缓存中清理过时的URL,将在安装更新的服务工作者后立即执行。

    在这种情况下,是否有理由不将skipWaiting 设置为true?

    使用skipWaiting 有一个few risks,为了安全起见,我们在Workbox 中默认禁用它。 (它在较早的 sw-precache 生成的服务工作者中默认启用。)

    假设您的 HTML 是先缓存加载的(通常是最佳实践),然后在加载后的某个时间检测到 Service Worker 更新。

    风险 1:延迟加载指纹内容

    现代网络应用程序通常结合两种技术:仅在需要时异步延迟加载资源(例如,在单页应用程序中切换到新视图)和添加指纹(哈希)以根据 URL 包含的内容唯一标识 URL。

    传统上,要么是 HTML 本身(或一些包含在页面生命周期早期加载的路由信息​​的 JavaScript)包含对需要延迟加载的当前 URL 列表的引用。

    假设最初加载的 Web 应用程序版本(在 Service Worker 更新发生之前)认为需要加载 URL /view-one.abcd1234.js 才能呈现 /view-one。但与此同时,您已经部署了代码更新,并且在您的服务器和预缓存清单中,/view-one.abcd1234.js 已被 /view-one.7890abcd.js 替换。

    如果skipWaiting 为真,那么/view-one.abcd1234.js 将作为activate 事件的一部分从缓存中清除。作为部署的一部分,您可能已经从服务器中清除了它。所以这个请求会失败。

    如果 skipWaiting 为 false,则 /view-one.abcd1234.js 将继续在您的缓存中可用,直到服务工作者的所有打开的客户端都已关闭。这通常是您想要的。

    注意:虽然使用 service worker 可能会使其更容易遇到此类问题,但对于所有延迟加载版本化 URL 的 Web 应用程序来说,这是一个问题。您应该始终进行错误处理以检测延迟加载失败并尝试通过例如强制重新加载页面来恢复。如果你有那个恢复逻辑,并且你对那个 UX 没问题,你可以选择启用skipWaiting

    风险 2:不兼容逻辑的延迟加载

    这与第一个风险相似,但它适用于您的网址中没有哈希指纹的情况。如果您为 HTML 部署更新并为您的一个视图部署相应更新,则现有客户端可以结束延迟加载与从缓存中获取的 HTML 结构不对应的/view-one.js 版本。

    如果skipWaiting 为假,那么这不太可能发生,因为从缓存加载的/view-one.js 应该对应于从同一个缓存加载的HTML 结构。这就是为什么它是一个更安全的默认设置。

    注意:和以前一样,这不是服务工作者独有的风险——任何动态加载未版本化 URL 的 Web 应用程序最终都可能在最近的部署之后加载不兼容的逻辑。

    那么clientsClaim是做什么的呢?

    clientsClaim 确保范围内的所有不受控制的客户端(即页面)在服务工作人员激活后立即由服务工作人员控制。如果您不启用它,那么直到下一次导航才会对其进行控制。

    启用它通常比skipWaiting 更安全,如果您希望服务工作者尽快开始填充运行时缓存,这会很有帮助。

    我会将您推荐给 Service Worker 生命周期文档中的 section 以获取更多信息。

    【讨论】:

    • 我认为您的第一个风险 1 不是 100% 正确的。当新的 service worker 代码和对 view-one 文件的更改上传到服务器时,安装/激活事件不会自动调用。所以如果用户点击 view-one 链接,他仍然会看到旧的 /view- one.abcd1234.js,因为它还没有从缓存中清除。如果浏览器刷新页面,Service Worker 会得到更新。当打开 2 个选项卡并且在服务器上更新视图一和 Service Worker 代码时,用户会刷新一个选项卡。现在,如果用户点击该路线,您的风险就会出现在第一个标签中,这是一个错误。有意义吗?
    • 当您提供预缓存的 HTML 和延迟加载子资源并调用 skipWaiting() 时,单个选项卡可能会发生风险 1。 “旧”预缓存 HTML 将用于在安装新 SW 之前完成导航,然后在安装新 SW 后,使用 skipWaiting() 意味着“旧” HTML 将引用哈希子资源不再预缓存。我在pawll.glitch.me 详细介绍了这一点
    • 我认为混淆点是当您说“如果浏览器刷新页面,SW 就会更新”,但事实并非如此。 SW 更新检查是异步的,并在导航期间开始,但当检查完成并检测到新的 SW 时,导航请求可能已经使用以前缓存的 HTML 完成。任何导航后都可以立即更新 SW。
    • 所以,@JeffPosnick 问题 1)通过导航你的意思是你执行 navigator.serviceWorker.register('/sw.js').then - 每次用户移动到我的网站的另一条路线或链接时,对?问题2)由于您在这方面经验丰富,您是否认为skipWaiting仅在应用程序是SPA时才有风险?除了您在此答案中解释的这两个风险之外,skipWaiting 还可能给我带来更多问题吗?问题 3)所以你建议在 SPA 的路由更改时将注册调用放在某种监听器中,对吗?
    • 问题 4) 。 redfin.engineering/… 如果你看看他使用的第一种方法,我认为他错了。 v1 不会尝试从网络加载样式,因为它已经在 v2 放置的缓存中。你不同意吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-25
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 2019-09-03
    • 2021-06-14
    相关资源
    最近更新 更多