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 被“唤醒”时,通过 push
或 sync
事件,浏览器
会同时请求最初传递到
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 部署任何内容的开发者阅读。