工作者线程的类型
- 专用工作者线程(Worker、或者称为 Web Worker):可以让脚本单独创建一个 JavaScript 线程,以执行委托的任务。
- 共享工作者线程(SharedWorker):共享工作者线程可以让多个不同的上下文使用,包括不同的的页面。任何与创建 SharedWorker 同源的脚本,都可以向 SharedWorker 发送消息
- 服务工作者线程(Service Worker):它与前面两者截然不同。它的主要用途是拦截、重定向和修改页面发出的请求,充当网络请求的仲裁角色。
范围、作用域
WorkerGlobalScope:由于在工作者线程内部,没有 window 的概念,这里的全局对象就是指的 WorkerGlobalScope
实例。并且它有以下子类:
- 专用工作者线程:DedicatedWorkerGlobalScope
- 共享工作者线程:SharedWorkerGlobalScope
- 服务工作者线程:ServiceWorkerGlobalScope
Service Worker 更类似于服务端的角色,它可以对前端的请求和资源的缓存进行控制
-
首先,需要使用 serviceWorkerContainer.register() 去注册。使用 navigator.serviceWorker 可以返回
serviceWorkerContainer
,并且注册成功的 service worker 会在 serviceWorkerGlobalScope 中执行,这是一种特殊的上下文,其中并不会有 DOM 权限 -
install
事件。用于安装 service worker。- 由于我们不希望同一 service worker 的两个不同版本同时运行,如果有先前的版本处于活动状态并打开页面,那么 service worker 的新版本不会运行
- 如果所有的 service worker 都已经关闭,那么才会安装新的 service worker。
- 如果要立即更新 service worker,可以使用 skipWaiting 去跳过等待,要求立即激活。
self.addEventListener("install", (event) => { self.skipWaiting() })
-
新的 service worker 会立即收到
activate
事件,该事件主要用于清理过时的 service worker。 -
激活后,service worker 会立刻控制只有那些在 register() 成功后打开的页面(文档必须重新加载才能真正的受控制,因为文档不管 service worker 是否存在的情况下就已经存在,并在其生命周期维护)。
如果我们使用 register()
注册成功,它会使用 ServiceWorkerRegistration 对象来兑现。
注意
- 在 HTTPS 下运行你的程序。
- service worker 文件的地址没有写对——需要相对于源(origin),而不是 app 的根目录。例如,worker 是在 https://mdn.github.io/sw-test/sw.js,app 的根目录是 https://mdn.github.io/sw-test/,你需要写成
/sw.js
。 - 不允许你的 app 指向不同源(origin)的 service worker。
- service worker 只能在 service worker 作用域里捕获客户端发出的请求。
- service worker 最大的作用域是 worker 所在的位置(换句话说,如果脚本
sw.js
位于/js/sw.js
中,默认情况下它只能控制/js/
下的 URL)。可以使用该 Service-Worker-Allowed 标头指定该 worker 的最大范围列表。
serviceWorkerGlobalScope,这是 service worker 的全局上下文。如果在 service worker 中,可以使用 self 代替。
- 例如 fetch、install、push 等
serviceWorkerContainer,它是由 navigator.serviceWorker 方法返回的。
controllerchange
:该事件在 ServiceWorkerRegistration 获取新的活动的 worker 时触发。message
:该事件用于在受控制的页面接收从 service worker 传来的消息
// event.data 用于接收 service worker 客户端传来的数据
navigator.serviceWorker.addEventListener('message', event => progress(event.data))
ServiceWorkerRegistration 实例,它是由 serviceWorkerContainer.register() 方法成功之后兑现的
updatefound
事件,该事件会在 ServiceWorkerRegistration.installing 获取新的 service worker 时触发。
reg.onupdatefound = function () {
const newSw = reg.installing
newSw.onstatechange = function () {
// 一直处于等待状态
if (newSw.state === 'installed') {
document.getElementById('new-service-worker-installed').style.display = 'block'
}
}
}
Service Worker 实例,它是由 ServiceWorkerRegistration 的
installing
(正在下载)、waiting
(等待)或者active
(已激活)属性返回。
error
,在 service worker 中发生错误时触发
if (navigator.serviceWorker) {
navigator.serviceWorker.register('service-worker.js');
navigator.serviceWorker.ready.then((registration) => {
registration.active.onerror = (event) => {
console.log('An error occurred in the service worker!')
}
})
}
statechange
:每当 ServiceWorker.state 更改时,statechange 事件都会触发。
self.clients.get(id).then((client) => {
self.clients.openWindow(client.url);
})
- postMessage(message, transfer?),该事件可以将数据从 service worker 中传递给受控页面
client.postMessage({ loaded, total })