4

引言

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体验相提并论,但是它的问题就是兼容性问题,相信如果兼容性问题得到解决,这种技术一定会被大面积推广到实际应用,希望通过这篇文章能对大家了解这门技术有一定的帮助。如果有错误或不严谨的地方,欢迎批评指正,如果喜欢,欢迎点赞。


william
2.7k 声望826 粉丝

love and share