引言
PWA(Progressive web apps, 渐进式Web应用),近两年被炒的十分火爆,它有什么优点呢?
- 可以生成桌面小图标,不需要打开浏览器,方便用户访问
- 通过网络缓存提升页面访问速度,达到渐进式的页面甚至离线访问,提升用户体验
- 实现类似app的推送功能,生成系统通知推送给用户
上面的这些优点足以让它吸引大量的开发者来探索和应用,毕竟对于web应用来说,用户体验才是检验web应用的好坏的至高标准,而PWA的这些优点恰恰是开发者在开发时一直追求的
Service Worker
service worker是实现PWA的核心,service worker是一个独立的浏览器线程,不会对当前程序的执行线程造成阻塞,通过service worker可以实现页面离线访问、用户消息推送等功能
生命周期
service worker生命周期完全独立于网页,因此,要想网页中使用service worker,需要先注册,注册后浏览器会在后台启动相关的安装步骤,一般情况下,我们需要service worker缓存一些静态文件,因此安装过程中会对指定的静态文件进行缓存,若缓存成功,则service worker安装成功,若中间有任何一个文件缓存失败,则service worker安装失败,会在下次重启时再次尝试,下面来看一个具体的生命周期图(来源[https://developer.mozilla.org...]()):
简单应用
看来上面的介绍,是不是跃跃欲试呢?接下来将用代码来简单使用一下service worker,缓存页面中的css、js文件,具体例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="/cache1.css">
<title>pwa</title>
</head>
<body>
<div id="app">test1</div>
<!-- built files will be auto injected -->
<script src='/cache1.js'></script>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js').then((registration) => {
console.log('Service Worker Registration')
}, (err) => {
console.log(err)
})
})
}
self.addEventListener('fetch', () => {
console.log('ss')
})
</script>
</body>
</html>
sw.js:
var cacheName = 'my-cache'
var cacheList = ['/cache1.css', '/cache1.js']
self.addEventListener('install', function(event) {
event.waitUntil(
// 安装成功后向caches中存入需要缓存的文件
caches.open(cacheName).then(function (cache) {
return cache.addAll(cacheList)
})
)
});
// 监听service worker fetch
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// 在缓存中查找到匹配的请求,就从缓存返回
if (response) {
console.log(response)
return response;
}
// 缓存中没有查找到对应请求,继续网络请求
return fetch(event.request);
}
)
);
})
如上例所示,利用service worker缓存了页面请求中cache1.js、cache1.css,然后再刷新一下网页,网页请求就会变成下图这样:
在网络请求面版可以很清楚看到这两个文件是从ServiceWorker中请求出来的,可能有些人对caches这个缓存对象还不是很了解,这有一篇文章可以帮助大家理解:传送门
vue-cli3中的pwa
vue最新脚手架中集成了pwa的插件,将pwa的实现变得更加的简单,只需要在vue.config.js文件中配置pwa属性就可以自动生成对应的service-worker.js配置文件,配置参考:传送门,这里面最核心的就是集成了google团队开发的Workbox,因此关于更加详细的pwa配置可以参考:传送门,这里面包含workbox所有配置项,这里面需要关注的是runtimeCaching属性,这个属性提供五种缓存策略:
- CacheFirst:优先取缓存中的数据,若没有则请求网络,请网络也失败就会报错
- CacheOnly:只从缓存中获取,若没有则报错
- NetworkFirst:优先从网络获取,若没有则从缓存中获取,缓存获取失败则报错
- NetworkOnly:只从网络获取,若没有则报错
- StaleWhileRevalidate:同时从网络与缓存获取,如果缓存可用,取缓存数据,否则从网络中请求,同时缓存会随着网络请求而更新
更加详细的缓存策略可以参考传送门,这里的缓存策略还需要注意的一个问题就是同源策略的问题,一般情况下workbox不会缓存跨域的资源请求,因为在缓存跨域资源时,workbox无法检测跨域请求是否成功,如果失败,用户将无法获取响应数据,但是在NetworkFirst和StaleWhileValidate策略下,可以缓存跨域资源,因为这两个策略的缓存会定期更新,即便出现失败请求,缓存的时间也是短暂的,具体详情可以参考传送门
兼容性
ServiceWorker这么牛,是不是就没有什么问题了呢,它最大的问题应该就是它的兼容性问题了,iOS11.3之前都不支持,具体详情参考:传送门,因此vue脚手架在集成时默认在ios下是关闭的
总结
PWA确实是当下很热门的技术,因为它提升了web应用的体验,甚至达到可以和原生app体验相提并论,但是它的问题就是兼容性问题,相信如果兼容性问题得到解决,这种技术一定会被大面积推广到实际应用,希望通过这篇文章能对大家了解这门技术有一定的帮助。如果有错误或不严谨的地方,欢迎批评指正,如果喜欢,欢迎点赞。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。