Progressive Web Applications
Progressive Web Applications take advantage of new technologies to bring the best of mobile sites and native applications to users. They're reliable, fast, and engaging.
基础知识
用户首次访问service worker控制的网站或页面时,service worker会立刻被下载。
ServiceWorker(web worker 的一种)接口
Cache:表示对request/response对象的存储,一个域可以有多个 Cache 对象. 你将在你的代码中处理和更新缓存 . 在 Cache 除非显示地更新缓存, 否则缓存将不会被更新; 缓存数据不会过期, 除非删除它
Cache.match(request, options)返回一个Promise,查找cache中匹配的request
Cache.match(request, options)匹配一个数组对象中的request
Cache.add(request)发送请求并将请求放入cache中,
Cache.put(request, response)将request和response都添加到cache中
Cache.delete(request, options) 才cache中查找乡音的值,并删除返回一个promise,resoleve为true,如果找不到返回false
Cache,keys(request, options)返回一个promise,resolve为所有的cache键值
CacheStorage: 对Cache对象的存储,提供命名缓存的主目录,sw可以通过访问并维护名字字符串到Cache对象的映射
caches.open(cacheName).then(names){};//打开一个cache对象
Client: 表示sw client的作用域。
sw.js中的self:这个关键字表示的是一个service worker 的执行上下文的一个全局属性(ServiceWorkerGlobalScope),类似于window对象,不过这个self是作用于service worker的全局作用域中。
sw生命周期
覆盖率
注意点
- 基于https
可以使用http-server+ngrok配合,当然更简单的使用github。
2.Service worker是一个注册在指定源和路径下的事件驱动worker。实际上 SW 在你网页加载完成同样也能捕获已经发出的请求,所以,为了减少性能损耗,我们一般直接在 onload 事件里面注册 SW 即可。 - 作用域问题
SW 的作用域不同,监听的 fetch 请求也是不一样的。 例如,我们将注册路由换成: /example/sw.js,那么,SW 后面只会监听 /example 路由下的所有 fetch 请求,而不会去监听其他
register
if(navigator.serviceWorker){
navigator.serviceWorder.register('sw.js')
.then(registration => {
console.log(`registered event at scope:${registration.scope}`);
})
.cache(err => {
throw err;
})
}
install
self.addEventListener('install', function(event) {
// Perform install steps
});
缓存文件
const cacheVersion = 'v1';
const cacheList = [
'/',
'index.html',
'logo.png',
'manifest.json',
'/dist/build.js'
];
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(cacheVersion).then(function(cache) {
return cache.addAll([cacheList]);
})
);
});
event.waitUntil()参数必须为promise,它可以延长一个事件的作用时间,因为我们在打开缓存或者更新的时候很有可能会有延迟,而event.waitUntil()可以防止事件终端。另外它会监听所有的异步promise,一旦有一个reject那么该次event便是失败的,也就是说sw启动失败。当然如果有些文件比较大不好缓存的话别让它返回就好了:
cache.addAll([cachelist1]);
return cache.addAll([cachelist2]);
fetchEvent
缓存捕获,当发起请求的时候将request和response缓存下来(缓存一开始定义的缓存列表)。
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then(response => {
if(response){
return reponse;
}
return fetch(event.request);
})
)
})
这是个比较简单的格式,event.respondWith(r),包含请求响应代码,可以设置一个参数r,r是一个promise,resolve之后是一个response对象。整段代码意思就是当请求一个文件时,如果缓存中已经有了,那么就直接返回缓存结果,否则发起请求。
问题:如果没有缓存我们怎么处理?
- 等下次sw根据路由去缓存;
- 手动缓存
手动缓存
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
if(response){
return response;
}
//fetch请求的request、response都定义为stream对象,所以只能读一次这里需要clone一个新的
let requestObj = event.request.clone();
return fetch(requestObj)
.then(response => {
//检测是否成功
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
//如果请求成功,第一要去渲染,第二要缓存
//cache.put()也使用stream,所以这里也需要复制一份
let responseObj = response.clone();
caches.open(cacheVersion)
.then(cache => {
cache.put(event.request, responseObj);
});
return response;
})
})
)
})
为什么stream只能读一次?
当可读流读取一次之后可能已经读到stream结尾或者stream已经close了,这里request和response都实现了clone接口来复制一份,所以在需要二次使用stream的时候就需要用副本来实现了。
删除旧的缓存
self.addEventListener('activate', evnet => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.filter(cachename => {
if(cachename == cacheVersion){
return caches.delete(cachename);
}
})
).then(() => {
return self.clients.claim()
})
})
)
})
我们检查之前保存的sw缓存,还要注意一点就是Promise.all()中不能有undefined,所以我们对于相同的版本要过滤,因而不使用map,避免返回undefined。
通过调用 self.clients.claim() 取得页面的控制权, 这样之后打开页面都会使用版本更新的缓存。
更新
当你更新了你的sw文件,并修改了cacheVersion之后,刷新浏览器,期待的变化并没有发生,因为虽然你改变了缓存版本,但是此时旧的sw还在控制整个应用,新的sw并没有生效。这时就需要更新一下sw,有以下方法
- registration.update() ,也就是在注册的时候选择合适方式更新
navigator.serviceWorker.register('/sw.js').then(reg => {
// sometime later…
reg.update();
});
- 使用self.skipWaiting();
在install阶段使用这个可以使得新的sw立即生效。
self.addEventListener('install', event => {
self.skipWaiting();
event.waitUntil(
// caching
);
});
- 调试手动更新
直接点击update即可。
注意,我们更新了某些文件的时候也要同时更新sw中的缓存版本(cacheVersion)
manifest文件
这个文件主要是配置添加到桌面的一些基本信息,比如图标启动页等。详细可以看这个https://developer.mozilla.org/zh-CN/docs/Web/Manifest
下面是我写的一个示例https://github.com/Stevenzwzhai/vue2.0-elementUI-axios-vueRouter/blob/master/pwa/sw.js
或者拉取这个项目https://github.com/Stevenzwzhai/PWA-demo
最近写了个知乎日报的pwa,有兴趣可以看下一篇文章
项目地址https://github.com/Stevenzwzhai/zhihu-daily
演示地址https://stevenzwzhai.github.io/zhihu-daily/
Progressive Web Applications的更多相关文章
- Model-View-Controller(MVC) is an architectural pattern that frequently used in web applications. Which of the following statement(s) is(are) correct?
Model-View-Controller(MVC) is an architectural pattern that frequently used in web applications. Whi ...
- 说说 PWA 和微信小程序--Progressive Web App
作者:云图图链接:https://zhuanlan.zhihu.com/p/22578965来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 利益相关:微信小用户,谷歌小 ...
- [io PWA] keynote: Launching a Progressive Web App on Google.com
Mainly about Material design (effects / colors / flashy stuff) Components (web components / polymer) ...
- Progressive Web Apps入门
PC和Mobile开发技术演进 PC方向,从客户端到富客户端,到现在广泛使用的Web. 移动方向,目前主要还是原生应用和Mobile Web,PWA相关技术是未来发展方向. PWA的概念 ...
- Developing RIA Web Applications with Oracle ADF
Developing RIA Web Applications with Oracle ADF Purpose This tutorial shows you how to build a ric ...
- 关于PWA ( Progressive web apps )
渐进式Web应用程序使用现代Web API以及传统的渐进式增强策略来创建跨平台Web应用程序.这些应用程序无处不在,并提供多种功能,使其具有与本机应用程序相同的用户体验优势.这套文档告诉您需要了解的所 ...
- (转)PWA(Progressive Web App)渐进式Web应用程序
PWA 编辑 讨论 PWA(Progressive Web App)是一种理念,使用多种技术来增强web app的功能,可以让网站的体验变得更好,能够模拟一些原生功能,比如通知推送.在移动端利用标准化 ...
- Setting up Scatter for Web Applications
[Setting up Scatter for Web Applications] If you are still using scatter-js please move over to scat ...
- Progressive web app理念及发展前景
前一段时间微信推出微信小程序进行公测,着实火了一把,博得了大众的眼球,不明真相的吃瓜观众们纷纷围观,所谓的“微信小程序”,通俗的讲就是一种不需要下载安装即可使用的应用程序,脱离于app商店依托于浏览器 ...
随机推荐
- 50、html补充
今天补充几个html标签 <body>内常用标签 1.<div>和<span> <div></div> : <div>只是一个块 ...
- SSH连接工具:SecureCRT设置,另一个SSH连接工具:Xshell。在Windows和Linux之间互传文件可用WinSCP
一般Linux发行版不允许root远程登录,CentOS允许. 调整字体大小:
- HTML5 给图形绘制阴影(绘制五角星示例)
几个属性 shadowOffsetX:阴影的横向位移量. shadowOffsetY:阴影的纵向位移量. shadowColor:阴影的颜色. shadowBlur:阴影的模糊范围. 属性说明 sha ...
- SpringMVC处理multipart请求.
一.简述 multipart格式的数据会将一个表单拆分为多个部分(part),每个部分对应一个输入域.在一般的表单输入域中,它所对应的部分中会放置文本型数据,但是如果上传文件的话,它所对应的部分可以是 ...
- Jmeter非GUI模式运行
非GUI模式,即命令行模式,运行 JMeter 测试脚本能够大大缩减所需要的系统资源. 使用的命令: jmeter -n -t 脚本文件路径 -l 结果输出文件路径 -j 日志文 ...
- 安装MySQL时提示3306端口已被占用的解决方案
之前安装过mysql,用的好好的,但是今天开启服务时报异常,无法启动.为省事,于是想到卸载重装,安装过程中发现3306已经被占用,这也是一开始服务无法启动的原因. 看到有人说用fport查看端口号,于 ...
- PS字体倾斜、变形
整体效果: 学习地址:http://www.wzsky.net/html/Photo/psjc/psc/125890_1.html 第一步新建画布,这个大家必须会,输入文字"基"基 ...
- Struts2-整理笔记(四)Action生命周期、如何获取参数(3种)、集合类型参数封装
一.Action生命周期 每次请求到来时,都会创建一个新的Action实例 Action是线程安全的,可以使用成员变量接收参数 二.获取参数的方式(3种) 1.属性驱动获得参数 每次请求Action时 ...
- Webpack 2 视频教程 014 - 深入理解 Webpack 2 中的 loader
原文发表于我的技术博客 这是我免费发布的高质量超清「Webpack 2 视频教程」. Webpack 作为目前前端开发必备的框架,Webpack 发布了 2.0 版本,此视频就是基于 2.0 的版本讲 ...
- (转)Linux安装Tomcat
为了学习java,需要一个服务器,因此决定用比较流行的tomcat.根据网上对安装tomcat的介绍,自己进行了安装,现在已经成功了,现在把安装的过程进行记录,也供大家学习参考. 一.从官方网站上 ...