Service Worker是什么
Service Worker
是一个注册在指定源和路径下的事件驱动 worker。它采用JavaScript控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。你可以完全控制应用在特定情形(最常见的情形是离线)下的表现。
Service Worker作用
Service Worker 中我们可以做很多事情,比如拦截客户端的请求、向客户端发送消息、向服务器发起请求等等,其中最重要的作用之一就是离线资源缓存 ([淘宝]、[网易新闻])
Service Worker特征
- Service Worker 工作在 worker context 中,是没有访问 DOM 的权限的,所以我们无法在 Service Worker 中获取 DOM 节点,也无法在其中操作 DOM 元素;
- 我们可以通过
postMessage
接口把数据传递给其他 JS 文件; - Service Worker 中运行的代码不会被阻塞,也不会阻塞其他页面的 JS 文件中的代码
Service Worker
运行在worker上下文,因此它不能访问DOM。相对于驱动应用的主JavaScript线程,它运行在其他线程中,所以不会造成阻塞。它设计为完全异步,同步API(如XHR和localStorage)不能在service worker中使用。
出于安全考量,Service workers只能由HTTPS承载,毕竟修改网络请求的能力暴露给中间人攻击会非常危险。
使用Service Worker
上面说到 Service Worker
必须使用https协议,但本地开发弄个https协议是很麻烦的。好在还算人性化,Service Worker在http://localhost或者http://127.0.0.1这种本地环境下的时候是可以跑起来的。
注册安装
下面就让我们来使用 Service Worker 。
如果当前使用的浏览器支持 Service Worker ,则在 window.navigator 下会存在 serviceWorker 对象,我们可以使用这个对象的 register 方法来注册一个 Service Worker。
这里需要注意的一点是,Service Worker 在使用的过程中存在大量的 Promise ,对于 Promise 不是很了解的同学可以先去看一下相关文档。 Service Worker 的注册方法返回的也是一个 Promise 。
// index.js
if ('serviceWorker' in window.navigator) {
navigator.serviceWorker.register('./sw.js', { scope: './' })
.then(function (reg) {
console.log('success', reg);
})
.catch(function (err) {
console.log('fail', err);
});
}
复制代码
在这段代码中,我们先使用 if 判断下浏览器是否支持 Service Worker ,避免由于浏览器不兼容导致的 bug 。
register 方法接受两个参数,第一个是 service worker 文件的路径,请注意:这个文件路径是相对于 Origin ,而不是当前 JS 文件的目录的;第二个参数是 Serivce Worker 的配置项,可选填,其中比较重要的是 scope 属性。按照文档上描述,它是 Service Worker 控制的内容的子目录,这个属性所表示的路径不能在 service worker 文件的路径之上,默认是 Serivce Worker 文件所在的目录;
register 方法返回一个 Promise 。如果注册失败,可以通过 catch 来捕获错误信息;如果注册成功,可以使用 then 来获取一个 ServiceWorkerRegistration 的实例,有兴趣的同学可以去翻阅文档。
注册完 Service Worker 之后,浏览器会为我们自动安装它,因此我们就可以在 service worker 文件中监听它的 install 事件了。
// sw.js
this.addEventListener('install', function (event) {
console.log('Service Worker install');
});
复制代码
同样的,Service Worker 在安装完成后会被激活,所以我们也可监听 activate 事件。
// sw.js
this.addEventListener('activate', function (event) {
console.log('Service Worker activate');
});
复制代码
这时,我们可以在 Chorme 的开发者工具中看到我们注册的 Service Worker。
在默认情况下,Service Worker 必定会每24小时被下载一次,如果下载的文件是最新文件,那么它就会被重新注册和安装,但不会被激活,当不再有页面使用旧的 Service Worker 的时候,它就会被激活。
这对于我们开发来说是很不方便的,因此在这里我勾选了一个名为 Update on reload 的单选框,选中它之后,我们每次刷新页面都能够使用最新的 service worker 文件。
在同一个 Origin 下,我们可以注册多个 Service Worker。但是请注意,这些 Service Worker 所使用的 scope 必须是不相同的。
if ('serviceWorker' in window.navigator) {
navigator.serviceWorker.register('./sw/sw.js', { scope: './sw' })
.then(function (reg) {
console.log('success', reg);
})
navigator.serviceWorker.register('./sw2/sw2.js', { scope: './sw2' })
.then(function (reg) {
console.log('success', reg);
})
}
复制代码
兼容性
从这张图中,我们可以看到 IE 和 Opera Mini 全面扑街,而主流浏览器中 Edge 17以下不支持,Safair 和 IOS Safair 刚刚开始支持,而火狐和 Chrome 支持良好。所以大家可以放心的使用,不过最好还是做一下判断。