默认情况下,较新的 Service Worker

tl;dr

从 Chrome 68 开始,检查 Service Worker 脚本更新的 HTTP 请求将不再 HTTP 缓存 默认情况。这种方法解决了常见的开发者痛点, 这样,在 Service Worker 脚本上无意中设置 Cache-Control 标头可能会导致 延迟更新。

如果您已通过传送 /service-worker.js 脚本来为其停用 HTTP 缓存 Cache-Control: max-age=0,则应该不会看到任何变化,因为新的默认值 行为

此外,从 Chrome 78 开始,逐字节比较将是 应用于通过 importScripts()。 对已导入的脚本所做的任何更改都会触发 Service Worker 更新流程, 就像更改顶级 Service Worker 一样。

背景

每次导航到 Service Worker 范围内的新页面时,明确调用 registration.update() 或当 Service Worker 被“唤醒”时,通过 pushsync 事件,浏览器 会同时请求最初传递到 navigator.serviceWorker.register() 调用,用于查找对 Service Worker 脚本的更新。

在本文中,我们假设该网址为 /service-worker.js, 包含对 importScripts() 的单个调用, 用于加载在 Service Worker 内运行的其他代码:

// Inside our /service-worker.js file:
importScripts('path/to/import.js');

// Other top-level code goes here.

有何变化?

在 Chrome 68 之前,对 /service-worker.js 的更新请求将通过 HTTP 缓存发出 (与大多数提取一样)。这意味着,如果脚本最初是使用 Cache-Control: max-age=600 发送的,则接下来的 600 秒(10 分钟)内的更新不会发送到网络,因此 用户可能无法收到最新版本的 Service Worker。但是,如果 max-age 是 超过 86400(24 小时),则会被视为 86400,以避免用户卡在 特定版本。

从 68 开始,请求 Service Worker 更新时将忽略 HTTP 缓存 脚本,因此现有的网络应用可能会发现其 Service Worker 脚本。对 importScripts 的请求仍将通过 HTTP 缓存进行。但这是 只是默认设置 - 新的注册选项 updateViaCache 可用, 。

updateViaCache

现在,开发者可以在调用 navigator.serviceWorker.register() 时传入一个新选项:updateViaCache 参数。 它接受以下三个值之一:'imports''all''none'

这些值决定了浏览器的标准 HTTP 缓存是否以及如何进行 在发出 HTTP 请求以检查更新的 Service Worker 资源时派上用场。

  • 如果设置为 'imports',则在检查对 /service-worker.js 脚本,但在提取任何导入的脚本时会参考 (在我们的示例中为 path/to/import.js)。这是默认值,与 。

  • 如果设置为 'all',则在同时针对 顶级 /service-worker.js 脚本,以及在服务内导入的所有脚本 例如 path/to/import.js。此选项对应之前在 Chrome 中的行为 Chrome 68 之前的版本。

  • 如果设置为 'none',则在针对 顶级 /service-worker.js 或任何导入的脚本,例如假设的 path/to/import.js

例如,以下代码将注册一个 Service Worker,并确保 HTTP 缓存是 在检查 /service-worker.js 脚本的更新或任何 通过 /service-worker.js 内的 importScripts() 引用的脚本:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js', {
    updateViaCache: 'none',
    // Optionally, set 'scope' here, if needed.
  });
}

检查导入的脚本是否有更新

在 Chrome 78 之前,通过 importScripts() 只能检索一次(首先检查 HTTP 缓存或通过 网络,具体取决于 updateViaCache 配置)。之后, 应由浏览器在内部存储,绝不会重新提取。

强制已安装的 Service Worker 获取对 更改脚本网址的方法,通常是在 semver 值(例如 importScripts('https://example.com/v1.1.0/index.js')),也可以添加 内容(例如 importScripts('https://example.com/index.abcd1234.js'))。答 更改导入的网址有一个副作用,那就是顶级 Service Worker 脚本的内容发生更改,进而触发 Service Worker 更新流程

从 Chrome 78 开始,每次针对顶级服务执行更新检查时 Service Worker 文件,系统会同时进行检查以确定 或所有已导入的脚本的内容均未更改。根据 使用了 Cache-Control 个标头,这些导入的脚本检查可能由 如果 updateViaCache 设置为 'all''imports'(即 使用默认值),否则,在发生以下情况时,检查可能会直接针对网络: updateViaCache 设置为 'none'

如果对已导入的脚本的更新检查导致逐字节出现差异 Service Worker 之前存储的数据,这将反过来 会触发完整的 Service Worker 更新流程,即使顶级 Service worker 文件保持不变。

Chrome 78 的行为与 Firefox implemented的行为一致 。Safari 已实现此行为 。

开发者需要做什么?

如果您已通过传送 /service-worker.js 脚本来有效地为其停用 HTTP 缓存 使用 Cache-Control: max-age=0(或类似值),则应该不会因 新的默认行为

如果您在启用 HTTP 缓存的情况下传送 /service-worker.js 脚本,则可能是有意为之 或者因为它只是托管环境的默认设置, 您可能会看到针对/service-worker.js的额外 HTTP 请求数量激增 您的服务器 - 这些是以前由 HTTP 缓存处理的请求。如果您想 继续允许 Cache-Control 标头值影响 /service-worker.js 时,您需要在满足以下条件时明确设置 updateViaCache: 'all': 注册 Service Worker。

考虑到旧版浏览器可能会有长尾用户,因此 请继续在 Service Worker 脚本上设置 Cache-Control: max-age=0 HTTP 标头,即使 较新的浏览器可能会忽略它们。

开发者可以借此机会决定是否要明确启用其导入的 脚本立即从 HTTP 缓存中退出,并将 updateViaCache: 'none' 添加到其 Service Worker 中 (如果适用)。

传送导入的脚本

从 Chrome 78 开始,开发者可能会看到更多针对 通过 importScripts() 加载的资源,因为它们现在要检查 更新。

如果您想避免这些额外的 HTTP 流量,请将长期有效 在传送包含 semver 或哈希值的脚本时,使用 Cache-Control 标头 其网址,并依赖于 'imports' 的默认 updateViaCache 行为。

或者,如果您希望系统频繁检查导入的脚本 更新,请确保通过Cache-Control: max-age=0投放它们、 或使用 updateViaCache: 'none'

深入阅读

Service Worker 生命周期”和 “缓存最佳做法和max-age 问题", 这两篇文章均由 Jake Archibald 撰写,建议所有向 Web 部署任何内容的开发者阅读。