原文地址:https://developers.google.com/web/updates/2019/09/fresher-sw 作者:Jeff Posnick
从 Chrome 68 开始,service worker 脚本检查更新的HTTP请求将默认不受 HTTP cache 的影响。这可以解决开发人员的共同难题,即在 service worker 脚本上设置无意的 Cache-Control 标头可能导致的更新延迟。
如果你已经使用Cache-Control: max-age=0
为/service-worker.js
脚本指定了HTTP缓存,那么由于新的默认行为,你应该不会看到/service-worker.js
脚本任何更改。
此外,从Chrome 78开始,service worker中对于通过importScripts()加载的脚本将逐字节进行比较。对导入脚本的任何更改都会触发service worker更新流程,就像对顶级service worker发生改变一样。
当每次访问一个service worker作用域下的新页面时,通过从JavaScript中显示得调用registration.update()
或者通过push
或sync
事件来"唤醒"该service worker时,浏览器将并行请求最初由navigator.serviceWorker.register()
请求的JavaScript资源,以更新service worker脚本。
出于本文的目的考虑,我们先假设其URL为/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缓存的影响(包含大多数的fetch请求)。这就意味着,如果最初脚本的请求存在请求头Cacha-Control: max-age=600
,接下来的600秒(10分钟)内脚本将不会通过网络进行更新,因此用户可能不会更新到service worker的最新版本。但是如果max-age大于86400(24小时),则将其视为86400,以避免用户永远被某个特定版本所困扰。
译者注:service worker 存在一个更新机制,至少一天会更新一次。
从Chrome 68开始,更新service worker脚本时,HTTP缓存将被忽略,因此,68版本后的浏览器中可以看到Web应用对其service worker脚本的请求频率增加,但importScripts的请求仍受HTTP缓存影响,并提供了一个新的注册选项updateViaCache
来控制这种行为。
在Chrome 68以后,开发者可以在调用navigator.serviceWorker.register()
时传递新参数:updateViaCache
,其有三个可选值:imports
,all
,none
。
这些值决定了对于检查 service worker 更新而发出HTTP请求,浏览器的HTTP缓存是否起作用以及如何发挥作用。
imports
时,HTTP缓存将不会影响/service-worker.js
的更新,但会影响service worker中引入的脚本(在我们的例子中是指path/to/import.js
)。这是Chrome 68之后版本的默认项。all
时,HTTP缓存将影响从顶级/service-worker.js
脚本中发出的所有请求,包括引入的脚本,例如:path/to/import.js
。此选项对应于Chrome 68之前版本的行为。none
时,HTTP缓存将不会影响从顶级/service-worker.js
脚本中发出的所有请求,包括引入的脚本,例如假想的path/to/import.js
。例如,以下代码将注册service worker
,并确保在检查更新/service-worker.js
脚本或通过importScripts()
引用的任何脚本时,其不受HTTP缓存影响。
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js', {
updateViaCache: 'none',
// Optionally, set 'scope' here, if needed.
});
}
在Chrome 78之前的版本,通过importScripts()
引入的service worker脚本将仅被检索一次(检查是使用HTTP缓存还是通过网络请求,者取决于updateViaCache
的值)。最初的获取之后,它将被浏览器存储在内部,并且永远不会重新获取。
仅仅有一种方式可以强制更新已经安装的service worker引入的脚本就是更新其URL,通常是通过添加一个semver值(例如 importScripts('https://example.com/v1.1.0/index.js'))或通过包含内容的哈希值(例如 importScripts('https://example. com/index.abcd1234.js'))。更改导入的URL的副作用是service worker脚本的内容发生了更改,这又触发了service worker的更新流程。
从Chrome 78开始,每次对service worker脚本执行更新检查时,都将同时检查导入脚本的内容是否已更改。如果updateViaCache
被设置为all
或者imports
(默认值),对于引入的脚本将根据其使用的Cache-Control
头部来进行检查更新。如果updateViaCache
被设置为none
,对于引入的脚本将直接通过网络请求获取。
如果是逐字节地与由service worker引入并暂存的脚本比对而引起的更新,即使顶级service worker文件保持不变,也将触发完整的service worker更新流程。
Chrome 78的行为与几年前Firefox 56在Firefox中实现的行为相同。Safari也已经实现了此行为。
如果你通过使用Cache-Control: max-age=0
(或类似值)为/service-worker.js
脚本有效地选择了HTTP缓存,那么不需要任何更改,因为这是默认行为。
如果想在/service-worker.js
脚本脚本中开启HTTP缓存,你想这样做或者这是你的默认环境的默认行为,你或许会看到/service-worker.js
中向服务器发送的命中HTTP缓存的请求数量增加。如果想让Cache-Control
头部影响/service-worker.js
的更新,则当你注册service worker的时候需要显示地设置updateViaCache: 'all'
。
考虑到浏览器版本升级需要些时间,因此即使在较新的浏览器上可以忽略它们,但依然推荐在service worker脚本上设置Cache-Control: max-age=0
HTTP头。
开发者可以利用这个时机来决定是否要从HTTP缓存中显式选择导入的脚本,如果合适的话可以在其service worker注册时添加updateViaCache:'none'
。
从Chrome 78开始,由于需要检查更新importScripts()
加载的资源,开发者或许会看到更多通过importScripts()
加载的资源的HTTP请求。
如果想避免这种额外的HTTP流量,可以在脚本的URL中包含semver
或hash
,并设置长效的Cache-Control
头,并使用默认的updateViaCache: "imports"
行为。
另外,如果希望检查导入的脚本经常更新,请确保为它们提供Cache-Control: max-age=0
,或者使用updateViaCache: 'none'
。
对于Web开发者,建议阅读Jake Archibald的The Service Worker Lifecycle和Caching best practices & max-age gotchas。