一个新的前端技术,PWA( 全称:Progressive Web App )也就是说这是个渐进式的网页应用程序。
官网:https://developers.google.com/web/progressive-web-apps/
是 Google 在 2015 年提出,2016年6月才推广的项目。是结合了一系列现代Web技术的组合,在网页应用中实现和原生应用相近的用户体验。官网上给出 PWA 的宣传是 : Reliable ( 可靠的 )、Fast( 快速的 )、Engaging( 可参与的 )
Reliable :当用户从手机主屏幕启动时,不用考虑网络的状态是如何,都可以立刻加载出 PWA。
Fast:这一点应该都很熟悉了吧,站在用户的角度来考虑,如果一个网页加载速度有点长的话,那么我们会放弃浏览该网站,所以 PWA 在这一点上做的很好,他的加载速度是很快的。
Engaging : PWA 可以添加在用户的主屏幕上,不用从应用商店进行下载,他们通过网络应用程序 Manifest file 提供类似于 APP 的使用体验( 在 Android 上可以设置全屏显示哦,由于 Safari 支持度的问题,所以在 IOS 上并不可以 ),并且还能进行 ”推送通知”
二、PWA应用于原生APP对比优缺点
三、PWA应用 PWA关键技术
Service Worker (可以理解为服务工厂)
Manifest (应用清单)
Push Notification(推送通知)
Service Worker
以下用SW来表示
SW 是什么呢?这个是离线缓存文件。我们 PWA 技术使用的就是它!SW 是浏览器在后台独立于网页运行的脚本,它打开了通向不需要网页或用户交互的功能的大门,因为使用了它,才会有的那个 Reliable 特性吧,SW 作用于 浏览器于服务器之间,相当于一个代理服务器。
**顺便带一句:**目前只能在 HTTPS 环境下才能使用SW,因为SW 的权利比较大,能够直接截取和返回用户的请求,所以要考虑一下安全性问题。
功能(还是比较逆天的)
后台数据的同步
从其他域获取资源请求
接受计算密集型数据的更新,多页面共享该数据
客户端编译与依赖管理
后端服务的hook机制
根据URL模式,自定义模板
性能优化
消息推送
定时默认更新
地理围栏
npm install web-pwa
// 或者使用 yarn
yarn add web-pwa
首先说明一下,我们要完成的目标:
整个代码如下:
import SW,{Notify,WebCaches} from 'web-pwa';
window.onload = function(){
SW.register('sw.js');
var tableName = 'prefetch-cache-v1';
WebCaches.table(tableName).addRow('/app.js')
.then(res=>{
// res: 成功
})
Notify.request() // 请求推送权限
.then(permission=>{
// 用户同意
Notify.show('villianhr','Hello Pwa')
.onclick(event=>{
event.close(); // 关闭当前 Notification
Notify.focus(); // 聚焦窗口
})
})
}
基本使用可以分为三块:
CacheStorage
缓存的相关操作。new Notification()
来完成主线程 JS 的消息推送import SW,{WebCaches,Notify} from 'web-pwa';
(重点推荐使用 WebCaches) 在内部细节中,处理了兼容性和权限请求的问题,这里我们具体落实到场景当中。
SW 原意是 Service Worker
。如果大家还不熟悉,推荐可以参考:Service Worker 全面进阶。
权限申请
SW.register('sw.js')
.then(reg=>{
})
它返回的是 Promise 对象。
销毁 Service Worker
SW.unregister().then(res=>{
if(res)console.log('unregisteration, done!');
})
它返回的是 Promise 对象。
Service Worker 更新
SW.update();
消息通信
我们了解 Service Worker 是继承 Web Worker
。在 Web Worker
中,我们可以使用 postMessage
进行通信,那么在 SW(Service Worker)中同样是可以的。
SW.postMessage('a new message send to Service Worker');
如果你想接受此次 SW 回复的信息,可以直接加上 Promise
的写法。
// 接收 SW 回复的信息
SW.postMessage('a new message send to Service Worker')
.then(reply=>{
// doSth
})
// SW 回复信息
self.addEventListener('message', function(event){
console.log("SW Received Message: " + event.data);
event.ports[0].postMessage("SW Says 'Hello back!'");
});
另外,SW 还可以通过 clients
挂载的 postMessage 向 client 发送信息。如果有这种需求,可以直接监听 message
事件。
SW.onmessage(event=>{
// 接收 SW 发送的消息
// event.data
})
推送订阅
当你想要使用 Push
相关的内容时,可以调用 Notify.subscribe(route,key)
方法。如果,你不是很理解 Web Push
的概念,可以参考: Web Push 讲解
// 下面的 key 根据自己生成进行替换
SW.subscribe('/subscription','BPLISiRYgXzzLY_-mKahMBdYPeRZU-8bFVzgJMcDuthMxD08v0cEfc9krx6pG5VGOC31oX_QEuOSgU5CYJqpzf0');
首先这里有两个概念,一个是 table(表),一个是 row(行)。每一个网站缓存可以有多个表,这完全取决于你自己的结构。该库是 one-off
形式,即,不能使用变量名来缓存表。例如:
var table = WebCaches.table('v1');
table.open(); // 正常执行没问题
table.open(); // 第二次使用无效
后面会介绍一种简便的方法进行简写。
缓存处理主要分为两块:
table
table 本身就是一个函数,构造格式为:
打开表
构造函数为:
WebCaches.table('demo-v1').open()
.then(cache=>{})
添加行
向表中添加具体的缓存行,添加方式有三种:
new Request(url)
实例化得来的。new Response(res)
生成,或者直接通过 fetch().then(response=>{})
获得的。重命名/复制表
重命名的格式为:
WebCaches.table('old-v1').rename('new-v2')
.then(res=>{
// success
})
.catch(err=>{
// fail
})
复制表的格式为:
// 将 A 表复制给 B
WebCaches.table('A').copyTo('B')
.then(res=>{
// success
})
.catch(err=>{
// fail
})
删除表
格式为:
WebCaches.table('A').delete()
.then(res=>{
// success
})
.catch(err=>{
// fail
})
row
row 本身也是一个函数:
origin
)。当为 request 时,是直接匹配对应的行记录,而为 pathname
时,则是使用 path-to-regexp 的格式,可以匹配多个或者模糊匹配。// 只匹配 js 文件
WebCaches.table(tableName).row('/*.js')
.get().then(res=>{
console.log(res);
})
通过 request 匹配:
var js = new Request('/app.js');
Caches.table(tableName).row(js)
.get().then(res=>{
console.log(res);
})
简写
如果每次都 WebCaches.table.row
这样调用,会让人觉得比较冗长,那么有没有什么好的办法解决呢?这里提供了一个工具函数 clone
用来生成可重复使用的对象。
// 提取 table
var table_v1 = WebCaches.clone('v1');
table_v1().open(); // first,OK
table_v1().open(); // second,OK
然后,可以提取 row
var table_row = WebCaches.clone('v1','/*.js');
table_row().get(); // first, OK
table_row().get(); // second, OK
删除行
// 删除所有 js 文件
WebCaches.table(tableName).row('/*.js')
.delete()
.then(()=>{
// success
})
.catch(err=>{
// fail
})
更新行
fetch('/')
.then(res=>{
// 更新根目录文件
WebCaches.table(tableName).row('/')
.update(res)
.then(()=>{
WebCaches.table(tableName).row('/').get()
.then(console.log.bind(console))
})
})
Notify
提供了 Notification
相关的 API。其主打的是链式调用,不需要过多的关注 Notification
内部细节。
权限申请
notify.request()
.then(permission=>{
// permission === "granted"
// permission === "denied"
// permission === "default"
})
消息推送
使用消息推送的时候,可以不用嵌套在 request()
里面,它内部已经做了权限的处理。
// 纯文字版
Notify.show('demo','this is a demo')
// 带 Icon
Notify.show('demo','this is a demo','demo.png')
推送后自动关闭
Notify.show('demo','this is a demo')
.hide(3000); // 3s 后自动关闭
推送点击
Notify.show('demo','this is a demo')
.onclick(e=>{
e.target.close();
});
Notify 还提供了其它的事件监听
上面这些方法都可以进行链式调用。
Notify.show('demo','this is a demo')
.onclick(event=>{})
.onclose(event=>{})
.onshow(event=>{})
用户点击推送这一行为,我们可以加上额外的处理,例如,打开页面,聚焦页面等。
Notify.show('demo','this is a demo')
.onclick(event=>{
event.target.close();
// 聚焦页面
Notify.focus();
// 打开新的页面
Notify.open('https://www.villainhr.com');
})
MIT
none