Service Worker 101

Service Worker 基础

前世今生

旧时代的http模式

web社区对离线模式的尝试

app manifest的问题

最终废弃

新的方案

SW 兼容性

SW 优势

什么是service worker

service worker 是独立于当前页面的一段运行在浏览器后台进程里的脚本。service worker不需要用户打开 web 页面,也不需要其他交互,异步地运行在一个完全独立的上下文环境,不会对主线程造成阻塞。基于service worker可以实现消息推送,静默更新以及地理围栏等服务。service worker提供一种渐进增强的特性,使用特性检测来渐渐增强,不会在老旧的不支持 service workers 的浏览器中产生影响。通过service workers可以让应用程序能够离线工作。

注意事项:

  • 出于安全考量,Service workers只能由HTTPS承载,毕竟修改网络请求的能力暴露给中间人攻击会非常危险。(特意预留localhost域名的权限供开发人员调试)
  • service worker运行在它们自己的完全独立异步的全局上下文中。
  • service worker没有直接操作DOM的权限,但是可以通过postMessage方法来与Web页面通信,让页面操作DOM。
  • service worker是一个可编程的网络代理,允许开发者控制页面上处理的网络请求。(劫持)
  • 浏览器可能随时回收service worker,在不被使用的时候,它会自己终止,而当它再次被用到的时候,会被重新激活。(采用事件驱动模式,休眠降低资源占用)
  • service worker的生命周期是由事件驱动的而不是通过Client。
  • chrome://serviceworker-internals/ 可以查看所有注册的SW

service worker生命周期

Service Worker 可能拥有以下六种状态的一种:解析成功(parsed),正在安装(installing),安装成功(installed),正在激活(activating),激活成功(activated),废弃(redundant)

  • 注册:注册过程独立于网页,先在页面执行注册,之后在浏览器后台启动安装步骤。
  • 安装:通常需要缓存某些静态资源。当所有文件已成功缓存,则安装完毕。如果任何文件下载失败或缓存失败,则安装失败,无法激活。
  • 激活:管理旧缓存的绝佳机会。激活后它将会对作用域页面实时控制,不过首次注册该服务工作线程的页面需要再次加载才会受其控制。
  • 控制时:处于两种状态之一: 1.终止以节省内存; 2.监听获取 fetch 和消息 message 事件。
  • 销毁:由浏览器决定,因此尽量不要留存全局变量。

解析成功(Parsed)

首次注册 Service Worker 时,浏览器解决脚本并获得入口点。如果解析成功(而且满足其他条件,如 HTTPS 协议),就可以访问到 Service Worker 注册对象(registration object),其中包含 Service Worker 的状态及其作用域。

index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    // 检查浏览器是否对 serviceWorker 有原生支持
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', function() {
      // register 方法里第一个参数为要加载的js;第二个参数 scope 可选,用来指定 Service Worker 控制的内容的子目录
        navigator.serviceWorker.register('./sw.js')
        .then(registration => {
          // Service Worker 注册成功
          console.log('ServiceWorker registration successful with scope: ', registration.scope)
        })
        .catch(err => {
          // Service Worker 注册失败
          console.log('ServiceWorker registration failed: ', err)
        })
      })
    }

安装(Installing)

在 installing 状态中,Service Worker 脚本中的 install 事件被执行。我们通常在安装事件中,为 document 缓存静态文件。

sw.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 缓存版本名
var CACHE_NAME = 'cache-v1'
// 待缓存资源列表
var urlsToCache = [
  '/',
  '/cache/style.css',
  '/cache/img.gif'
]

// 在已注册的sw脚本内部,拥有caches和self全局对象(对应缓存和sw自身)
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      return cache.addAll(urlsToCache)
    })
  )
})

若事件中有 event.waitUntil() 方法,则 installing 事件会一直等到该方法中的 Promise 完成之后才会成功;若 Promise 被拒,则安装失败,Service Worker 直接进入废弃(redundant)状态。

激活成功(Activated)

如果 Service Worker 处于激活态,就可以应对事件性事件 —— fetch 和 message。

sw.js

1
2
3
4
5
6
7
8
// 监听并劫持fetch
self.addEventListener('fetch', event => {  
  // do something
});

self.addEventListener('message', function(event) {  
  // do something with postMessages received from document
}); 

废弃(Redundant)

Service Worker 可能以下之一的原因而被废弃

  • installing 事件失败
  • activating 事件失败
  • 新的 Service Worker 替换其成为激活态 worker

使用场景

架构革命

可复用的app shell

利用SW监控网页崩溃

https://zhuanlan.zhihu.com/p/40273861

Service workers还可以用来做这些事情:

  • 后台数据同步
  • 响应来自其它源的资源请求
  • 集中接收计算成本高的数据更新,比如地理位置和陀螺仪信息,这样多个页面就可以利用同一组数据
  • 在客户端进行CoffeeScript,LESS,CJS/AMD等模块编译和依赖管理(用于开发目的)
  • 后台服务钩子
  • 自定义模板用于特定URL模式
  • 性能增强,比如预取用户可能需要的资源,比如相册中的后面数张图片

未来service workers能够用来做更多使web平台接近原生应用的事。 值得关注的是,其他标准也能并且将会使用service worker

算不上demo的demo: https://send.firefox.com/download/9560d98052/#VaIjDVyXH3SxxeYsn4PKgw

Licensed under CC BY-NC-SA 4.0
Built with Hugo
主题 StackJimmy 设计