json

2018-06-04 16:09

PWA之离线缓存(一)

本文作者:IMWeb json 原文出处:IMWeb社区 未经同意,禁止转载

PWA是什么

PWA全称是Progressive Web Apps, 是一种渐进式增强 WEB 应用。 这里的渐进式增强是指无论用户用的是什么浏览器都能保证应用能正常工作。

PWA特性:

  • 渐进增强 : 能够让每一位用户使用,无论用户使用什么浏览器,因为它是始终以渐进增强为原则
  • 可安装 : 可以像原生APP在主屏幕上留有图标。
  • 离线缓存 :通过Service Worker使得 Web App 也可以做到像 Native App 那样可以离线使用、消息推送的功能。
  • 安全性 : 通过 HTTPS 来提供服务来防止网络窥探,保证内容不被篡改。

PWA是应用一系列技术组成的集合, 其核心技术包括 App Manifest、Service Worker、Web Push等等。

Service Worker详解

service worker是什么?

service worker是独立于当前页面的运行在浏览器后台进程的脚本。利用它,我们可以拦截页面请求,缓存文件。 使用service worker有几点注意:

  • 页面必须基于https
  • 独立于当前网页进程,不会对主线程造成影响
  • 不能操作DOM,但可以通过postMessage与页面通信
  • 可以拦截作用域范围内的所有请求

浏览器支持情况

可以看出大部分现代浏览器都已经得到了支持。

生命周期

从图中可以看出,用户访问某个URL的时候, 服务器返回相应的资源文件,此时会调用navigator.serviceWorker.register('/teacher/sw.js') , 下载sw.js 。 执行sw。如果出现错误。serviceWorker会被废弃掉。 当执行完sw文件后,出触发install事件, 此时可以调用cache API去缓存想要的静态资源 。 注意, 如果缓存失败, serviceWorker也将装载失败 。 待serviceWorker装载完成后, 触发activate事件。serviceWorker准备就绪。 此时可以监听fetch事件拦截浏览器请求了。

demo

 <html>
    <head>
        <title>pwa test</title>
    </head>
    <body>
        hello world;
        <script>
          if ('serviceWorker' in navigator) {             
            navigator.serviceWorker.register('/teacher/sw.js').then(function (registration) {

              console.log('ServiceWorker registration successful with scope: ', registration.scope);
            }).catch(function (err) {                     
              // 注册失败 :(
              console.log('ServiceWorker registration failed: ', err);
            });
          }
          setTimeout(() => {
            const img = new Image();
            img.src = "/teacher/1@2x_d3458ef8fd9ebd0f7fe4ab1f886b572f.gif";
            document.body.appendChild(img);
          }, 3000);
        </script>
    </body>
</html>

如图html文件中,可以在文件末尾插入如上代码来注册service worker。

  • sw 是挂载到navigator对象上的, 使用之前先判断是否存在
  • 作用域:SW 的默认作用域为基于当前文件 URL 的 ./, 如果想要改变作用域,可以使用scope eg:

 navigator.serviceWorker.register('/teacher/sw.js', {scope: '../..'})

sw.js文件如下:


self.addEventListener('install', (event) => {
  console.log('V1 installing…11', event);

  event.waitUntil(
    caches.open("static-v1").then(cache => cache.add("https://7.url.cn/fudao/pc/bd3fa67732209940a5ca1db12970e41e.png"))
  );
});

self.addEventListener('activate', (event) => {
  console.log('V1 now ready to handle fetches!12');
});

self.addEventListener("fetch", event => {
  const url = new URL(event.request.url);
  console.log(33333, event.request);
});

监听install事件, 缓存资源文件。 如果都缓存成功,那么OK,service worker安装成功。 这里缓存资源时, 定义了一个缓存名字static-v1 , 打开这个缓存,将图片文件添加进去。

离线资源更新

1、如果业务的静态资源更新了, 需要修改sw.js文件,一个B的修改都会引起浏览器的重新下载sw文件, 然后触发install , 装载新的离线资源。 但要注意,新的service worker不会立即activate , 因为老的service worker还在, 新的sw处于waiting状态。

必须关闭当前sw控制的所有页面,然后再访问当前页面才能使新的sw激活。 比较麻烦。 解决办法是 使用 self.skipWaiting();来跳过等待,直接使用新的sw激活。

self.addEventListener('install', (event) => {
  self.skipWaiting();
  console.log('V1 installing…11', event);

2、如果更改sw, 什么时候会触发新的sw的下载呢, 答案是刷新页面的时候 。 我们做资源缓存, 发布文件后不能要求用户一定刷新页面, 如果停留在一个页面较长时间, 但仍然想使用新的缓存资源,该怎么做呢? 可以在注册的时候调用update()方法


navigator.serviceWorker.register('/teacher/sw.js').then(function (registration) {
     setInterval(function() {
         console.log('setInterval');
         registration.update();
     }, 4000);
     // 注册成功
     console.log('ServiceWorker registration successful with scope: ', registration.scope);
 }).catch(function (err) {                     
     // 注册失败 :(
     console.log('ServiceWorker registration failed: ', err);
 });

每隔固定的4s, 实际使用中可以更长时间, 去下载一次sw, 结合skipWaiting , 可以实现体验更好的缓存资源的更新 。

待续

关于缓存策略、上报方案等实践,敬请期待。

0条评论

    您需要 注册 一个IMWeb账号或者 才能进行评论。