在讲Service Worker之前先说一下另一个概念:PWA(Progressive Web Apps)
Progressive Web App:是一个具有响应式布局的Web应用,可以离线工作,并能够安装到设备的主屏幕上。其实是在主屏幕上添加该Web应用的快捷方式。
Service Worker:一个Service Worker是一段运行在浏览器后台进程里的脚本,他独立于当前页面,提供了那些不需要与web页面交互的功能在网页背后悄悄执行的能力。在将来,基于它可以实现消息推送,静静更新以及地理围栏等服务,但是目前它首先要具备的功能是拦截和处理网络请求的功能,包括可编程的消息缓存管理能力,是PWA的核心。
1.网络代理,转发请求,伪造响应
2.离线缓存
3.消息推送
4.后台消息传递
学习service worker之前,需注意以下地方:
Service worker拥有一个完全独立于Web页面的生命周期。要让一个service worker在你的网站上生效,你需要先在你的网页中注册它。注册一个service worker之后,浏览器会在后台默默启动一个service worker的安装过程。在安装过程中,浏览器会加载并缓存一些静态资源。如果所有的文件被缓存成功,service worker就安装成功了。如果有任何文件加载或缓存失败,那么安装过程就会失败,service worker就不能被激活(也即没能安装成功)。如果发生这样的问题,别担心,它会在下次再尝试安装。
当安装完成后,service worker的下一步是激活,在这一阶段,你还可以升级一个service worker的版本,具体内容我们会在后面讲到。
在激活之后,service worker将接管所有在自己管辖域范围内的页面,但是如果一个页面是刚刚注册了service worker,那么它这一次不会被接管,到下一次加载页面的时候,service worker才会生效。
当service worker接管了页面之后,它可能有两种状态:要么被终止以节省内存,要么会处理fetch和message事件,这两个事件分别产生于一个网络请求出现或者页面上发送了一个消息。
service worker初次安装的生命周期:
如图可知:service worker要经历以下过程:
1. 安装
2. 激活,激活成功之后,打开chrome://inspect/#service-workers可以查看到当前运行的service worker
3. 监听fetch和message事件,下面两种事件会进行简要描述
4. 销毁,是否销毁由浏览器决定,如果一个service worker长期不使用或者机器内存有限,则可能会销毁这个worker
在页面发起http请求时,service worker可以通过fetch事件拦截请求,并且给出自己的响应。在前端开发中通过fetch事件拦截请求是很基本的技术。
w3c提供了一个新的fetch api,用于取代XMLHttpRequest,与XMLHttpRequest最大不同有两点:
1. fetch()方法返回的是Promise对象,通过then方法进行连续调用,减少嵌套。ES6的Promise在成为标准之后,会越来越方便开发人员。
2. 提供了Request、Response对象,如果做过后端开发,对Request、Response应该比较熟悉。前端要发起请求可以通过url发起,也可以使用Request对象发起,而且Request可以复用。但是Response用在哪里呢?在service worker出现之前,前端确实不会自己给自己发消息,但是有了service worker,就可以在拦截请求之后根据需要发回自己的响应,对页面而言,这个普通的请求结果并没有区别,这是Response的一处应用。
事例:
/* API URL, you need to supply your API key */
var URL = 'https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=your_api_key&format=json&nojsoncallback=1&tags=penguins';
function fetchDemo() {
fetch(URL).then(function(response) {
return response.json();
}).then(function(json) {
insertPhotos(json);
});
}
fetchDemo();
页面和serviceWorker之间可以通过posetMessage()方法发送消息,发送的消息可以通过message事件接收到。这是一个双向的过程,页面可以发消息给service worker,service worker也可以发送消息给页面,由于这个特性,可以将service worker作为中间纽带,使得一个域名或者子域名下的多个页面可以自由通信。
只有通过service workder缓过得文件,只要你访问过一次,下一次均可实现离线访问,再也不会404了。
if
(navigator.serviceWorker)
{
navigator.serviceWorker.register('service-worker.js').then(function(registration)
{console.log('service worker 注册成功');
}).catch(function
(err)
{console.log('servcie worker 注册失败')});
}
在上述代码中,注册了service-worker.js作为当前路径下的service worker。
注:由于service worker的权限很高,所有的代码都需要是安全可靠的,所以只有https站点才可以使用service worker,当然localhost是一个特例。
2. 写service-worker.js代码
根据前面的生命周期图,在一个新的service worker被注册以后,首先会触发install事件。可以通过监听install事件做一些初始化工作。
因为我们是要缓存离线文件,所以可以在install事件中开始缓存。
var cacheFiles=
[ 'about.js',
'blog.js'
首先定义了需要缓存的文件数组cacheFile,然后在install事件中,缓存这些文件。
// 缓存图片
self.addEventListener('fetch',
function
(evt)
{ evt.respondWith(caches.match(evt.request).then(function(response)
{
if(response)
{
//.....
}
evt是一个InstallEvent对象,继承自ExtendableEvent,其中的waitUntil()方法接收一个promise对象,直到这个promise对象成功resolve之后,才会继续运行service-worker.js。caches是一个CacheStorage对象,使用open()方法打开一个缓存,缓存通过名称进行区分。
获得cache实例之后,调用addAll()方法缓存文件。这样就将文件添加到caches缓存中,然后使用fetch事件拦截请求。首先检缓存中是否已经缓存了这个请求,如果有,就直接返回响应,就减少了一次网络请求。否则由service workder发起请求,这时的service workder起到了一个中间代理的作用。
Chrome | Firefox | IE | Opera | Safari | |
---|---|---|---|---|---|
基本功能 | 40.0 | 44.0 | 不支持 | 24 | 不支持 |
install/activate | 40.0 | 44.0 | 不支持 | 24 | 不支持 |
fetch event/request/respondWith | 40.0 | 44.0 | 不支持 | 不支持 | 不支持 |
caches/cache | 42.0 | 39.0 | 不支持 | 不支持 | 不支持 |
附:https://www.w3ctech.com/topic/866
认识Progressive Web App