2019独角兽企业重金招聘Python工程师标准>>>

在2014年,W3C公布了service worker的草案,service worker提供了很多新的能力,使得web app拥有与native app相同的离线体验、消息推送体验。
service worker是一段脚本,与web worker一样,也是在后台运行。作为一个独立的线程,运行环境与普通脚本不同,所以不能直接参与web交互行为。native app可以做到离线使用、消息推送、后台自动更新,service worker的出现是正是为了使得web app也可以具有类似的能力。

service worker可以:

  1. 后台消息传递
  2. 网络代理,转发请求,伪造响应

  3. 离线缓存

  4. 消息推送

  5. … …

本文以资源缓存为例,说明一下service worker是如何工作的。

生命周期

先来看一下一个service worker的运行周期


上图是service worker生命周期,出处http://www.html5rocks.com/en/tutorials/service-worker/introduction/

图中可以看到,一个service worker要经历以下过程:

1.  安装

2.  激活,激活成功之后,打开chrome://inspect/#service-workers可以查看到当前运行的service worker

3. 监听fetch和message事件,下面两种事件会进行简要描述

4. 销毁,是否销毁由浏览器决定,如果一个service worker长期不使用或者机器内存有限,则可能会销毁这个worker

fetch事件

在页面发起http请求时,service worker可以通过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的一处应用。

下面是在http://www.sitepoint.com/introduction-to-the-fetch-api/中,作者利用fetch api通过fliker的公开api获取图片的例子,注释中详细解释了每一步的作用:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

/* 由于是get请求,直接把参数作为query string传递了 */

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, option)支持两个参数,option中可以设置header、body、method信息

fetch(URL).then(function(response) {

// 通过promise 对象获得相应内容,并且将响应内容按照json格式转成对象,json()方法调用之后返回的依然是promise对象

// 也可以把内容转化成arraybuffer、blob对象

return response.json();

}).then(function(json) {

// 渲染页面

insertPhotos(json);

});

}

fetchDemo();

fetch api与XMLHttpRequest相比,更加简洁,并且提供的功能更全面,资源获取方式比ajax更优雅。兼容性方面:chrome 42开始支持,对于旧浏览器,可以通过官方维护的polyfill支持。

message事件

页面和serviceWorker之间可以通过posetMessage()方法发送消息,发送的消息可以通过message事件接收到。

这是一个双向的过程,页面可以发消息给service worker,service worker也可以发送消息给页面,由于这个特性,可以将service worker作为中间纽带,使得一个域名或者子域名下的多个页面可以自由通信。

这里是一个小的页面之间通信demohttps://nzv3tos3n.qnssl.com/message/msg-demo.html

利用service workder缓存文件

下面介绍一个利用service worker缓存离线文件的例子
准备index.js,用于注册service-worker

1

2

3

4

5

6

7

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是一个特例。
注册完毕,现在开始写service-worker.js代码。
根据前面的生命周期图,在一个新的service worker被注册以后,首先会触发install事件,在service-workder.js中,可以通过监听install事件进行一些初始化工作,或者什么也不做。
因为我们是要缓存离线文件,所以可以在install事件中开始缓存,但是只是将文件加到caches缓存中,真正想让浏览器使用缓存文件需要在fetch事件中拦截

1

2

3

4

5

6

7

8

9

10

11

var cacheFiles = [

'about.js',

'blog.js'

];

self.addEventListener('install', function (evt) {

evt.waitUntil(

caches.open('my-test-cahce-v1').then(function (cache) {

return cache.addAll(cacheFiles);

})

);

});

首先定义了需要缓存的文件数组cacheFile,然后在install事件中,缓存这些文件。
evt是一个InstallEvent对象,继承自ExtendableEvent,其中的waitUntil()方法接收一个promise对象,直到这个promise对象成功resolve之后,才会继续运行service-worker.js。
caches是一个CacheStorage对象,使用open()方法打开一个缓存,缓存通过名称进行区分。
获得cache实例之后,调用addAll()方法缓存文件。

这样就将文件添加到caches缓存中了,想让浏览器使用缓存,还需要拦截fetch事件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

// 缓存图片

self.addEventListener('fetch', function (evt) {

evt.respondWith(

caches.match(evt.request).then(function(response) {

if (response) {

return response;

}

var request = evt.request.clone();

return fetch(request).then(function (response) {

if (!response && response.status !== 200 && !response.headers.get('Content-type').match(/image/)) {

return response;

}

var responseClone = response.clone();

caches.open('my-test-cache-v1').then(function (cache) {

cache.put(evt.request, responseClone);

});

return response;

});

})

)

});

通过监听fetch事件,service worker可以返回自己的响应。

首先检缓存中是否已经缓存了这个请求,如果有,就直接返回响应,就减少了一次网络请求。否则由service workder发起请求,这时的service workder起到了一个中间代理的作用。

service worker请求的过程通过fetch api完成,得到response对象以后进行过滤,查看是否是图片文件,如果不是,就直接返回请求,不会缓存。

如果是图片,要先复制一份response,原因是request或者response对象属于stream,只能使用一次,之后一份存入缓存,另一份发送给页面。
这就是service worker的强大之处:拦截请求,伪造响应。fetch api在这里也起到了很大的作用。

service worker的更新很简单,只要service-worker.js的文件内容有更新,就会使用新的脚本。但是有一点要注意:旧缓存文件的清除、新文件的缓存要在activate事件中进行,因为可能旧的页面还在使用之前的缓存文件,清除之后会失去作用。

在初次使用service worker的过程中,也遇到了一些问题,下面是其中两个

问题1. 运行时间

service worker并不是一直在后台运行的。在页面关闭后,浏览器可以继续保持service worker运行,也可以关闭service worker,这取决与浏览器自己的行为。所以不要定义一些全局变量,例如下面的代码(来自https://jakearchibald.com/2014/service-worker-first-draft/):

1

2

3

4

5

6

7

8

var hitCounter = 0;

this.addEventListener('fetch', function(event) {

hitCounter++;

event.respondWith(

new Response('Hit number ' + hitCounter)

);

});

返回的结果可能是没有规律的:1,2,1,2,1,1,2….,原因是hitCounter并没有一直存在,如果浏览器关闭了它,下次启动的时候hitCounter就赋值为0了
这样的事情导致调试代码困难,当你更新一个service worker以后,只有在打开新页面以后才可能使用新的service worker,在调试过程中经常等上一两分钟才会使用新的,比较抓狂。

问题2. 权限太大

当service worker监听fetch事件以后,对应的请求都会经过service worker。通过chrome的network工具,可以看到此类请求会标注:from service worker。如果service worker中出现了问题,会导致所有请求失败,包括普通的html文件。所以service worker的代码质量、容错性一定要很好才能保证web app正常运行。

参考文章:

1. http://www.html5rocks.com/en/tutorials/service-worker/introduction/

2. http://www.sitepoint.com/introduction-to-the-fetch-api/

3. https://developer.mozilla.org/en-US/docs/Web/API/InstallEvent

4. https://developer.mozilla.org/en-US/docs/Web/API/ExtendableEvent

5. https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage

转载于:https://my.oschina.net/wanjubang/blog/839436

Service Work相关推荐

  1. struts2 与 sping 整合 控制器中 service注入的问题

    以个人见解认为struts1 与spring整合的时候按照习惯,我们会把 action 控制器直接配置到sping中去: eg : 这里以使用元注解方式实现Service注入进行讲解: 控制器关键代码 ...

  2. java action dao_java中Action层、Service层和Dao层的功能区分

    一.Action/Service/DAO简介: Action是管理业务(Service)调度和管理跳转的. Service是管理具体的功能的. Action只负责管理,而Service负责实施. DA ...

  3. Android中Service生命周期、启动、绑定、混合使用

    一.Activity和Service如何绑定: 1.Service和Activity之间的连接可以用ServiceConnection来实现.实现一个ServiceConnection对象实例,重写o ...

  4. CentOS7下启动Nginx出现Failed to start nginx.service:unit not found

    错误的原因就是没有添加nginx服务,所以启动失败. 解决方法: 1.    在/root/etc/init.d/目录下新建文件,文件名为nginx 或者用命令在根目录下执行:# vim /etc/i ...

  5. CentOS7 service network start命令启动时报错解决方法

    service network start命令启动时报错: [root@localhost network-scripts]# service network start Starting netwo ...

  6. android Service 的使用

    1 Service 简介 Service 是Android 四大组件之一 一般在后台运行,无用户界面,用户无法看到. Service主要用于组件之间交互(例如:与Activity.ContentPro ...

  7. Web Service 安全性解决方案(SOAP篇)

    拼吾爱程序人生 » 软件编程 » Visual Studio.NET » Web Service » Web Service 安全性解决方案(SOAP篇) Web Service 安全性解决方案(SO ...

  8. Hibernate **关于hibernate4.3版本之后org.hibernate.service.ServiceRegistryBuilder被弃用**

    之前一直都是使用hibernate4.2.21的我,有一天突然没有使用本地的jar包而是让IDEA自动下载最新版本的hibernate5.2.2之后,发现有几个经常使用的方法报错了. //创建配置对象 ...

  9. [转]JAVA中Action层, Service层 ,modle层 和 Dao层的功能区分

    首先这是现在最基本的分层方式,结合了SSH架构.modle层就是对应的数据库表的实体类.Dao层是使用了Hibernate连接数据库.操作数据库(增删改查).Service层:引用对应的Dao数据库操 ...

  10. k8s nodeport无法访问_k8s学习之service详解

    1.概述 通过Deployment来创建一组Pod来提供具有高可用性的服务.每个Pod都会分配一个单独的Pod IP,却存在如下两问题: 1.pod ip仅仅集群内部可见的虚拟IP,外部无法访问 2. ...

最新文章

  1. 详解Numpy的广播机制
  2. 笔记-信息系统安全管理-信息安全(混合)
  3. mybatis应用(二)注解的实现
  4. Repeater嵌套绑定
  5. 取消myeclipse2017的Dashboard页面
  6. 原型设计工具:Axure RP Pro 4
  7. Spring Security使用出现 Encoded password does not look like BCrypt异常的解决以及Spring Securit加密方式的学习
  8. django orm 之makemigrations和migrate命令
  9. 山师计算机二级考试科目,山师计算机应用技术考试试题与答案.doc
  10. kafka in action
  11. JVM调优及调优参数详解
  12. 使用FFMPEG类库分离出多媒体文件中的H.264码流
  13. lr_save_var() 截取任意字符串长度,以参数形式输出(参数转变量)
  14. edittext 点击区域外隐藏输入法
  15. s7200cpu224xp手册_S7-200 PLC DC224XP DC DC DC的接线图说明
  16. Java类汽车,JAVA 建立一个汽车AutoMobile类......
  17. Python-爬虫(爬虫练习 爬取古诗文网五言绝句)
  18. WannaCry勒索病毒处理指南
  19. C语言 怎样定义指针变量
  20. unity 中打印照片的四种方法

热门文章

  1. 启动未初始化小应用程序_SpringBoot详细打印启动时异常堆栈信息
  2. 国内pinterest发展介绍------瀑布流效果
  3. The application's PagerAdapter changed the adapter's contents without calling notifyDataSetChanged
  4. 登录和oauth机制
  5. Nginx实现静态代理,负载均衡,前后端分离
  6. 水清冷冷:Adobe Illustrator CC 2021(AI CC2021)安装教程及学习技巧(附工具)
  7. shell的建立与执行实验报告_实验指导书--实验02 Linux Shell用户接口
  8. mysql建表语句主键自增_MYSQL索引-上
  9. 周长最短面积最大_圆内接三角形中,正三角形周长最大值的证明
  10. 计算机应用基础作业北语,北语计算机应用基础作业.doc