Service Worker 作用域

Service Worker 默认不能控制其上一级目录, Service-Worker-Allowed 指定的目录可以设置最大的 scope(超过它的上一级的限制)。

作用域污染

image.png

当同一个页面被多个 Service Worker 所控制,会导致一些问题。
在注册之前,注销所有的 Service Worker,防止 Service Worker 的作用域污染

  1. navigator.serviceWorker.getRegistrations().then(function (regs) {
  2. for (let reg of regs) {
  3. reg.unregister();
  4. }
  5. });

MPA 注册一个 Service Worker

  • 不会造成 Service Worker 污染。
  • 统一处理整站的离线缓存策略,降低维护成本。
  • Service Worker 需要统一管理,增加了项目开发的耦合性。

MPA 注册多个 Service Worker

image.png

  • Service Worker 维护上和页面关联,增加了灵活性。
  • 维护成本增加,风险相对会更大。
  • 可能造成 Servcie Worker 污染。
  • 不能统一的处理整站的离线缓存方案。

Service Worker 触发更新

  • 浏览器每 24 小时更新一次 Service Worker。(浏览器默认行为)
  • 注册新的 Service Worker,带上版本号,如:/sw.js?v=2018071920
  • 手动更新 registration.update()
  • 逐字节对比新的 sw 文件和旧的 sw 文件,有区别时才更新。

Service Worker 更新过程

  • 开始更新前,老的 SW 会总是激活。
  • 更新后的 SW 会和老的 SW 共同存在,新的 SW 进入 install 生命周期。
  • 如果新的 SW 没有 install 成功,它将被废弃,老的 SW 继续保持激活状态。
  • 一旦新的 SW 安装成功,它会进入 wait 状态直到老的 SW 不控制任何 clients(页面标签)。
  • self.skipwaiting() 可以跳过等待,让新 SW 安装成功后立即激活。

Service Worker 更新遇到的问题

  • SW 更新完成后,缓存在更新的过程中已经更新为最新的。
  • 页面静态资源在 SW 更新完成之前已经加载完成,所以还是老的。
  • JavaScript 可能有的接口在上线的时候有变动。
  • 如果请求接口是 Network Only 缓存策略的话会报错。

Service Worker 更新后通知用户

  1. self.addEventListener('activate', function (event) {
  2. // 进入 activate 生命周期,说明新的 SW 已经注册成功。
  3. let cacheName = 'a_cache_name';
  4. event.waitUntil(
  5. caches.open(cacheName)
  6. .then(function(cache){ // 进行老缓存的清除,代码省略
  7. .then(function(cache){
  8. // 这里可以判断如果 cache 里本来就没有内容,表示第一次安装,就不用通知用户了。
  9. return self.clients.matchAll()
  10. .then(function (clients){
  11. if (clients && clients.length) {
  12. clients.forEach(function(client){
  13. // 给每个已经打开的标签都 postMessage
  14. clients.postMessage("sw.update")
  15. })
  16. }
  17. })
  18. })
  19. })
  20. )
  21. });

在检测到页面的 SW 更新时,我们可以:

  • 直接 reload 页面(不建议)
  • 提醒用户更新
  1. if ('serviceWorker' in navigator) {
  2. navigator.serviceWorker.addEventListener('message', function(e) {
  3. if (e.data === 'sw.update') {
  4. // 以刷新当前页面为例
  5. // 刷新后 sw 为最新的 sw,页面内容也为最新的。
  6. window.location.reload()
  7. }
  8. })
  9. }

当 SW 文件被缓存,怎么使它更新?

后端设置 Cache-Control: no-cache;

image.png

前端更新的策略

image.png

Service Worker 兜底方案

Q:如果 Service Worker 在运行过程中出现了问题怎么办?
A:需要找个能快速上线的开关 JavaScript 文件。 https://yourhost.com/switch.js

image.png