PWA笔记

https://lavas.baidu.com/pwa/README

Progressive Web App, 简称 PWA,是提升 Web App 的体验的一种新方法,能给用户原生应用的体验。

PWA 能做到原生应用的体验不是靠特指某一项技术,而是经过应用一些新技术进行改进,在安全、性能和体验三个方面都有很大提升,PWA 本质上是 Web App,借助一些新技术也具备了 Native App 的一些特性,兼具 Web App 和 Native App 的优点。

PWA 的主要特点包括下面三点:

可靠 - 即使在不稳定的网络环境下,也能瞬间加载并展现
体验 - 快速响应,并且有平滑的动画响应用户的操作
粘性 - 像设备上的原生应用,具有沉浸式的用户体验,用户可以添加到桌面。

Web App Manifest

manifest 其实就是一个 json 文件manifest.json。它的作用:

  • 将 PWA 站点添加至桌面
  • 设置主屏幕启动时的过渡画面
  • 隐藏浏览器的相关 UI
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"short_name": "短名称",
"name": "这是一个完整名称",
"icon": [
{
"src": "icon.png",
"type": "image/png",
"sizes": "48x48"
}
],
"start_url": "index.html"
}

// 在文件中引用
<link rel="manifest" href="./manifest.json">

###service worker
创建一个注册文件sw-register.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if ("serviceWorker" in navigator) {
// 因为service worker需要启动一个新的线程,所以为了避免阻塞进程,在loader事件中执行。可以避免一些低配置的设置扛不住
window.addEventListener("load", function() {
navigator.serviceWorker
.register("/sw.js", { scope: "/" })
.then(function(registration) {
// 注册成功
console.log("ServiceWorker registration successful with scope: ", registration.scope);
})
.catch(function(err) {
// 注册失败:(
console.log("ServiceWorker registration failed: ", err);
});
});
navigator.serviceWorker.oncontrollerchange = function() {
showToast("页面已更新!");
};
if (navigator.online) {
showToast("网络已断开,内容可能已过期");
window.addEventListener("online", function() {
showToast("网络已连接");
});
}
}

sw.js 中注册 service worker 的事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 监听 service worker 的 install 事件
this.addEventListener('install', function (event) {
// event.waitUntil 回调函数 保证里面的所有操作执行完,安装才会结束。
event.waitUntil(
// 操作 CacheStorage 缓存,使用 caches.open() 打开一个对应缓存空间。
caches.open('my-test-cache-v1').then(function (cache) {
// 通过 cache 缓存对象的 addAll 方法设置缓存列表
return cache.addAll([
'/',
'/index.html',
'/main.css',
'/main.js',
'/image.jpg'
]);
}).then(function(){self.skipWaiting()});
);
});

// 安装成功后就该激活
this.addEventListener('activate', function (event) {
event.waitUntil(
Promise.all([
// 使首次加载的页面可以直接被控制
this.clients.claim();

// 激活后,获取缓存列表
caches.keys.then(function(cacheList){
return Promise.all(
cacheList.map(function(cacheName){
// 删除不必要的缓存
if(cacheName!=='my-test-cache-v1'){
return catches.delete(cacheName)
}
})
);
});
]);

);
});

service worker 激活后,就获取了对页面的所有控制权,但是 service worker 只能控制激活后打开的页面,因此首次激活这个 service worker 的页面是无法被控制的,因此如果首次加载的页面也想被 service worker 控制,则需要刷新下页面才行,为了实现首页和激活后打开的页面一样直接就被 service worker 控制,就需要使用this.clients.claim()

在 install 中缓存资源,在 activate 中删除没必要的缓存,在 fetch 中获取缓存中的资源,fetch 中也可以缓存资源。

缓存策略

  • Cache only
    资源直接从缓存中获取,获取不到,则请求失败。该模式假定资源之前已被缓存,可能 install 期间就做了缓存,比较适合静态资源。
  • Network only
    只从网络返回,适合前端用户行为日志大点之类的请求。
  • Cache,falling back to Network
    优先从 cache 返回内容,如果失败则从网络请求。
  • Network, falling back to cache
    优先从网络返回内容,如果失败了则从缓存获取。适用于频繁更新的内容,希望用户总是看到最新的内容。

注意

  • 避免使用 http 缓存
  • 最长 24 小时
  • 避免缓存跨域资源

工具 workbox

service worker 的工具https://github.com/googlechrome/workbox

消息通知

  • 查看通知权限
    在控制台输入下面命令,就可以查看当前网站的通知权限
1
Notification.permission;

权限值有三个:

  • default
  • granted
  • denied
  • 请求设置通知权限
1
Notification.requestPermission().then(permission => console.log(permission));

requestPermission 静态方法返回的是一个 promise 对象

  • 发送通知
    权限设置允许后,就可以发送通知了。
    Notification 的一个实例,就相当于发送一个通知。
1
new Notification("this is title", { body: "this is content." });

###service worker 中发送通知
在 service worker 中是不允许弹出提示,所以通知权限默认是 denied,不是 default。(可以在控制台中切换成service worker环境进行测试)
因为 service worker 控制是整个项目的请求,所以它不知道是哪个页面的通知。另外它也不允许控制 dom。
那该如何在 service worker 中发送通知呢?
只需要在页面中设置通知权限,然后在 service worker 中发送请求即可。
service worker 发送通知和在页面中发送通知不同。在 service worker 中不能把 Notification 当成构造函数来创建通知,使用下面方式:

1
self.registration.showNotification("hello")

registration就是注册 service worker 时生成的对象。

删除除 serviceWorker.js 之外的所有文件和文件夹,如果都是文件,可不加-dr

1
ls | grep -v serviceWorker.js | xargs rm -dr
文章作者: wenmu
文章链接: http://blog.wangpengpeng.site/2020/01/09/PWA%E7%AC%94%E8%AE%B0/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 温木的博客
微信打赏