Service Worker

简单来说,Service Worker 是一个可编程的 Web Worker,它就像一个位于浏览器与网络之间的客户端代理,可以拦截、处理、响应流经的 HTTP 请求。
配合随之引入 Cache Storage API,你可以自由管理 HTTP 请求文件粒度的缓存,这使得 Service Worker 可以从缓存中向 web 应用提供资源,即使是在离线的环境下。

生命周期

首先在创建Service Worker的网站需要先支持https。通过Service Worker可以劫持、伪造和过滤响应,为了避免这些问题,只能在HTTPS的网页上注册Service Worker。

与Web Worker不同的是Service Worker的生命周期完全独立与页面。即在页面上加载销毁的情况均不影响Service Worker的生命周期,关联页面未关闭时,它也可以退出,没有关联页面时,它也可以启动。

注册

Service Worker脚本通过 navigator.serviceWorker.register 方法注册到页面, 之后可以脱离页面在浏览器后台运行。

1
2
3
4
5
6
navigator.serviceWorker.register('service-worker.js', {scope: '/'})
.then(res => {
console.log('success');
}).catch(err => {
console.log('faile');
});

Service Worker脚本的作用范围不能超出脚本文件所在的路径。如果Service Worker注册的地址是网站的根目录,则可以直接拦截整个网站的请求。另外比如地址是 “/js/worker.js” 的脚本只能控制 “/js/“ 下的页面请求。

其中scope是用来表示注册的Service Worker在网站的哪个目录下面。如果Service Worker文件是在网站的根目录下但是scope却是注册在"/example/"下则Service Worker也只能收到"/example/"下的请求。

下载、安装和激活

在用户第一次访问一个Service Worker的网站的时候Service Worker会立刻被下载。之后每24小时会被重新下载一次,尽管可能在24小时之内被重复的下载。

如果是首次访问Service Worker的网站的话页面则直接会尝试安装,再安装成功之后会被激活。

如果是再已经启用的网站的话,Service Worker会在后台被安装但是并不会被激活。这个时序称为worker in waiting。直到所有已加载的页面不再使用旧的Service Worker才会激活新的Service Worker。只要页面不再依赖旧的Service Worker,新的Service Worker会被激活(成为active worker)。

你可以监听InstallEvent,事件触发时的标准行为是准备Service Worker用于使用,例如使用内建的storage API来创建缓存,并且放置应用离线时所需资源。当oninstall事件程序执行完毕后,就可以认为 Service Worker安装完成了。

1
2
3
4
5
// worker.js

self.addEventListener('install', event => {
console.log('worker installing…');
});

下一步是激活,当Service Worker安装完成之后会收到一个激活事件(activate event)。

Service Worker 现在可以控制页面了,但仅是在 register() 成功后的打开的页面。也就是说,页面起始于有没有Service worker, 且在页面的接下来生命周期内维持这个状态。页面需要重新加载以让Service worker获得完全的控制。

Service Worker版本

浏览器内核会管理三种Service Worker脚本版本:

  • installing_version:处于 INSTALLING 状态的版本
  • waiting_version: 处于 INSTALLED 状态的版本
  • active_version: 处于 ACTIVATED 状态的版本

installing_version 一般是在 service worker 线程启动后,即 ServiceWorkerVersion::StartWorker 返回 status 为 SERVICE_WORKER_OK 时,处于此版本状态,这是一个中间版本,在正确安装完成后会转入 waiting_version。

waiting_version 一般在注册信息已存储到数据库,即 ServiceWorkerStorage::StoreRegistration 返回 status 为 SERVICE_WORKER_OK 时,处于此版本状态。或者在再次打开 service worker 页面时,检查到 service worker 脚本版本的状态为 INSTALLED,也会进入此版本状态。waiting_version 的存在确保了当前 scope 下只有一个 active service worker。

active_version 一般在 activate 事件处理完成后,就会处于此版本状态,同一 scope 下只有一个 active Service Worker。需要特别注意的是,当前页面已有 active worker 控制,刷新页面时,新版本 Waiting(Installed) 状态的 service worker 并不能转入 active 状态。

Service worker 可以从 waiting_version 转入 active_version 的条件:

  • 当前 scope 下没有 active service worker 在运行。
  • 页面 JS 调用 self.skipWaiting 跳过waiting 状态。
  • 用户关闭页面,释放了当前处于 active 状态的service worker。
  • 浏览器周期性检测,发现 active service worker处于idle状态,就会释放当前处于active状态的service worker。

ServiceWorkerContainer

ServiceWorkerContainer接口为 service worker提供一个容器般的功能,包括对service worker的注册,卸载 ,更新和访问service worker的状态,以及他们的注册者。

hi you can see me