关键特性
- Web App Manifest – 在主屏幕添加app图标,定义手机标题栏颜色之类
- App Shell – 先显示APP的主结构,再填充主数据,更快显示更好体验
- Service Worker - 缓存,离线开发,以及地理位置信息处理等
- Push Notifion - 消息推送
Service Worker
运行在浏览器端的代理服务器
基本特点
- 事件驱动型服务线程
- 只能基于https或者localhost
- 可以控制页面所发送网络请求的处理方式
- 运行在浏览器后台的脚本,无法直接操作dom
生命周期
支持事件
register
- 在主线程代码中注册
- 可以指定scope,通常指定到网站根路径,能够拦截所有的fetch事件
- service worker 已经被注册过,浏览器会自动忽略上面的代码
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js', {
scope: '/'
}).then(function (reg) {
// 注册成功
console.log('success and scope: ', reg.scope);
}).catch(function (err) {
// 注册失败
console.log('failed: ', err);
});
});
}
installing
缓存文件
installed/waiting
此状态下,worker有效但尚未激活,它尚未纳入 document的控制,确切来说是在等待着从当前 worker 接手
sw.js发生了更新,但是页面一直挂载中,没有关闭或强制刷新,此时上一个版本的sw还在工作中,新的sw处于等待中
// 安装阶段跳过等待,直接进入 active
self.addEventListener('install', function (event) {
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', function (event) {
event.waitUntil(
Promise.all([
// 更新客户端
self.clients.claim()
])
);
});
activating/activated
缓存更新
fetch
代理请求
message
sw与主线程间的双向通信,建立MessageChannel
作为纽带
// index.html
navigator.serviceWorker.register('/service-worker.js', {
scope: '/'
}).then(function (reg) {
// 创建一个
const channel = new MessageChannel();
// port1供主线程使用
channel.port1.onmessage = messageEvent => {
console.log('来自sw的message', messageEvent.data);
}
const serviceWorker = reg.active;
// port2指向sw
if (serviceWorker) {
serviceWorker.postMessage('index->sw', [channel.port2]);
}
});
// sw.js
self.addEventListener('message', function (event) {
console.log('来自index的message', event.data);
// 通过port找到发送消息的client
event.ports[0].postMessage('sw->index');
});
更多的应用场景
- 后台数据同步
- 预取用户可能需要的资源,比如相册中的后面数张图片
- 在后台集中接收计算成本高的数据更新,比如地理位置和陀螺仪信息,多个页面就可以利用同一组数据
Cache API
- 只能缓存 GET 请求;
- 可以缓存属于自己域下的请求,同时也可以缓存跨域的请求,不过无法对跨域请求的Request和Response进行修改
- 缓存的更新需要自行实现
- 缓存不会过期,除非将手动删除,大小有限制,LRU删除
caches.open
创建一个cache
cache.add/addAll
- 支持传入Requesturl
- 缓存资源,支持单个和数组
- 在cache.add内部会自动去调用fetch取回request的请求结果,然后才是把response存入cache
cache.put
- 相当于cache.add的第二步,即fetch到response后存入cache
-
无法直接缓存跨域的请求,response.status会返回0
- 如果跨域的资源支持CORS,那么可以把request的mod改成cors
caches.match
catch.match(request, {
}).then(function(response) {
})
cache.delete
一些使用点
-
分段缓存,提高安装成功率
- 先安装非重要资源,再安装重要资源
-
渐进式缓存
- 对于在install时没有缓存的资源,可以在用户交互之后再缓存
-
优先原则
- 对于静态页面,缓存优先,减少请求
- 对于天气类型应用,先去fetch,服务器故障或者网络不良时,折回本地缓存
Manifest
一个基本的manifest.json
{
"short_name": "短名称",
"name": "这是一个完整名称",
"icon": [
{
"src": "icon.png",
"type": "image/png",
"sizes": "48x48"
}
],
"start_url": "index.html"
}
可以实现的功能
-
基本功能
- 自定义名称
- 自定义图标
- 设置启动网址
- 设置作用域
-
添加启动画面
- 设置显示类型
- 指定显示方向
- 设置主题色
-
应用安装横幅
-
站点部署 manifest.json,该文件需配置如下属性:
- short_name (用于主屏幕显示)
- name (用于安装横幅显示)
- icons (其中必须包含一个 mime 类型为 image/png 的图标声明)
- start_url (应用启动地址)
- display (必须为 standalone 或 fullscreen)
- 站点注册 Service Worker。
- 站点支持 HTTPS 访问。
- 站点在同一浏览器中被访问至少两次,两次访问间隔至少为 5 分钟。
-
Web Push
Notification
PushManager
- 询问授权
- 发送subscription给后端存储
- 服务端向FCM/GCM发送消息,同时带上subscription
- FCM根据subscription再下发给对应的浏览器
- 触发Service Worker的push事件
- 后续处理
参考
- https://segmentfault.com/a/11...
- https://x5.tencent.com/tbs/gu...
- https://lavas.baidu.com/pwa/o...
- http://www.zhangxinxu.com/wor...
- https://zhuanlan.zhihu.com/p/...
- https://github.com/delapuente...
- https://github.com/SangKa/PWA...
- 使用Service Worker发送Push推送
- https://fed.renren.com/2017/1...
- https://pwa.rocks/
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。