Service Worker初体验
概述
在讲Service Worker之前先说一下另一个概念:PWA(Progressive Web Apps) Progressive Web App:是一个具有响应式布局的Web应用,可以离线工作,并能够安装到设备的主屏幕上。其实是在主屏幕上添加该Web应用的快捷方式。 Service Worker:一个Service Worker是一段运行在浏览器后台进程里的脚本,他独立于当前页面,提供了那些不需要与web页面交互的功能在网页背后悄悄执行的能力。在将来,基于它可以实现消息推送,静静更新以及地理围栏等服务,但是目前它首先要具备的功能是拦截和处理网络请求的功能,包括可编程的消息缓存管理能力,是PWA的核心。
Service Worker
Service Worker作用
1.网络代理,转发请求,伪造响应 2.离线缓存 3.消息推送 4.后台消息传递
学前准备
学习service worker之前,需注意以下地方:
- 它是JavaScript Worker,所以它不能直接操作DOM。但是service worker可以通过postMessage与页面之间通信,把消息通知给页面,如果需要的话,让页面自己去操作DOM。
- Service worker是一个可编程的网络代理,允许开发者控制页面上处理的网络请求。
- 在不被使用的时候,它会自己终止,而当它再次被用到的时候,会被重新激活,所以你不能依赖于service worker的onfecth和onmessage的处理函数中的全局状态。如果你想要保存一些持久化的信息,你可以在service worker里使用IndexedDB API。
- Service worker大量使用promise,所以如果你不了解什么是promise,那你需要先阅读这篇文章。
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
fetch事件
在页面发起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();
message事件
页面和serviceWorker之间可以通过posetMessage()方法发送消息,发送的消息可以通过message事件接收到。这是一个双向的过程,页面可以发消息给service worker,service worker也可以发送消息给页面,由于这个特性,可以将service worker作为中间纽带,使得一个域名或者子域名下的多个页面可以自由通信。
service workder缓存文件
只有通过service workder缓过得文件,只要你访问过一次,下一次均可实现离线访问,再也不会404了。
- 准备index.js,用于注册service-worker
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
- Golang学习-第三篇 认识Web框架
- Golang学习-第二篇 搭建一个简单的Go Web服务器
- 数据说话:Go语言的Switch和Map性能实测
- Dora.Interception, 为.NET Core度身打造的AOP框架[4]:演示几个典型应用
- Dora.Interception, 为.NET Core度身打造的AOP框架[3]:Interceptor的注册
- Dora.Interception, 为.NET Core度身打造的AOP框架:不一样的Interceptor定义方式
- Dora.Interception,为.NET Core度身打造的AOP框架:全新的版本
- ASP.NET Core的路由[4]:来认识一下实现路由的RouterMiddleware中间件
- 浅谈 Java 并发编程中的若干核心技术
- ASP.NET Core的路由[3]:Router的创建者——RouteBuilder
- ASP.NET Core的路由[2]:路由系统的核心对象——Router
- ASP.NET Core的路由[1]:注册URL模式与HttpHandler的映射关系
- 学习ASP.NET Core, 怎能不了解请求处理管道[6]: 管道是如何随着WebHost的开启被构建出来的?
- 学习ASP.NET Core, 怎能不了解请求处理管道[5]: 中间件注册可以除了可以使用Startup之外,还可以选择StartupFilter
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux 创建子进程执行任务的实现方法
- Linux系统下安装jdbc与tomcat的图文教程
- Linux系统下利用C程序输出某进程的内存占用信息
- .NET Standard中配置TargetFrameworks输出多版本类库
- .NET Standard SDK 样式项目中的目标框架
- 偿还技术债(2)-EventBus自己实现一个?
- AkShare-债券数据-收盘收益率曲线
- Vue 项目报错:‘$‘ is not defined ( no-undef )
- SpringBoot 项目开启热部署
- 小程序文件下载并保存文件名打开
- 分享个 CTF 小工具 bruteHASH
- centos配置mutt和msmtp实现邮件发送
- CentOS8 安装 jdk8 / java8的教程(推荐)
- Ubuntu18.04 一键升级Python所有第三方包 及安装python包的方法
- 详解centos7上elastic search安装及填坑记