道招

PWA缓存控制和版本升级实践

如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!

PWA缓存控制和版本升级实践

PWA是会注册一个service-worker的,每次任何被 service worker 控制的资源被请求到时,都会触发 fetch 事件,这些资源包括了指定的 scope 内的文档,和这些文档内引用的其他任何资源(比如 index.html 发起了一个跨域的请求来嵌入一个图片,这个也会通过 service worker 。)

缓存

技术依据

file

我们可以给 service worker 添加一个 fetch 的事件监听器,接着调用 event 上的 respondWith() 方法来劫持我们的 HTTP 响应,然后你用可以用自己的方法来更新他们。

在任何情况下我们只是简单的响应这些缓存中的 url 和网络请求匹配的资源,比如下面的例子:

this.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
  );
});

caches.match(event.request) 允许我们对网络请求的资源和 cache 里可获取的资源进行匹配,查看是否缓存中有相应的资源。这个匹配通过 url 和 vary header进行,就像正常的 http 请求一样,如果没有在缓存中找到匹配的资源,你可以告诉浏览器对着资源直接去 fetch 默认的网络请求。

fetch(event.request)

如果没有在缓存中找到匹配的资源,同时网络也不可用,你可以用 match() 把一些回退的页面作为响应来匹配这些资源。

caches.match('/fallback.html');
最佳实践

我们不仅仅可以在fetch的回调里面尝试从缓存中匹配资源,也可以将从网络请求的资源存储在缓存中。

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(resp) {
      return resp || fetch(event.request).then(function(response) {
        return caches.open('v1').then(function(cache) {
          cache.put(event.request, response.clone());
          return response;
        });
      });
    })
  );
});

这里我们用 fetch(event.request) 返回了默认的网络请求,它返回了一个 promise 。当网络请求的 promise 成功的时候,我们 通过执行一个函数用 caches.open('v1') 来抓取我们的缓存,它也返回了一个 promise。当这个 promise 成功的时候, cache.put() 被用来把这些资源加入缓存中。资源是从 event.request 抓取的,它的响应会被response.clone() 克隆一份然后被加入缓存。这个克隆被放到缓存中,它的原始响应则会返回给浏览器来给调用它的页面。

我们之使用response.clone()是因为请求和响应流只能被读取一次。为了给浏览器返回响应以及把它缓存起来,我们不得不克隆一份。所以原始的会返回给浏览器,克隆的会发送到缓存中。它们都是读取了一次。

我们还可以加上一个回退方案,以便在缓存中找不到并且网络不可用的时候有内容返回给用户

this.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function() {
      return fetch(event.request).then(function(response) {
        return caches.open('v1').then(function(cache) {
          cache.put(event.request, response.clone());
          return response;
        });
      });
    }).catch(function() {
      return caches.match('/sw-test/gallery/myLittleVader.jpg');
    })
  );
});

升级

如果你的 service worker 已经被安装,但是刷新页面时发现有一个新版本的可用,新版的 service worker 会在后台install,但是还没active。当不再有任何已加载的页面在使用旧版的 service worker 的时候,新版本才会激活。

更新service-worker

install事件就派上用场了,我们可以改造下install事件的回调。

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v2').then(function(cache) {
      return cache.addAll([
        '/sw-test/',
        '/sw-test/index.html',
        '/sw-test/style.css',
        '/sw-test/app.js',
        '/sw-test/image-list.js',
        // ...
      ]);
    })
  );
});

当安装发生的时候,前一个版本依然在响应请求,新的版本正在后台安装,我们调用了一个新的缓存 v2,所以前一个 v1 版本的缓存不会被扰乱。

删除旧的缓存

这个时候activate事件就派上用场了,当之前版本还在运行的时候,一般被用来做些会破坏它的事情,比如摆脱旧版的缓存。

传给 waitUntil() 的 promise 会阻塞其他的事件,直到它完成。所以你可以确保你的清理操作会在你的的第一次 fetch 事件之前会完成。

self.addEventListener('activate', function(event) {
  var cacheWhitelist = ['v2'];

  event.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (cacheWhitelist.indexOf(key) === -1) {
          return caches.delete(key);
        }
      }));
    })
  );
});
版本升级小技巧

因为我们的版本号一般都是字符串形式,我们就需要让浏览器知道哪个是新版本了,比如v1.2是新版本还是说v1.11,从数值上看 2 < 11 ,但是很多系统一般是根据ASCII码进行排序的,这样就会让部分系统存在歧义了,我们应该从自己的角度上避免了。前叙述的例子改成v.1.021.11就消除了这种歧义。

一个简单的更新补丁版本的方法,大版本和小版本类似。

function updateVersion(version) {
  const lastVersion = getCurrentVersion(version);
  const [main, sub, fix] = lastVersion.split('.');
  const fixNum = parseInt(fix) + 1 + '';
  const newVersion = [main, sub, fixNum.padStart(4, '0')].join('.');
  return [lastVersion, newVersion];
}
更新时间:
上一篇:从PWA消息推送调试经历来看PWA现状,PWA凉了,凉透了吗?下一篇:Android摸索记录--获取android联系人

相关文章

凡客联盟会员猛增,联盟实行收款账户信息升级

尊敬的凡客联盟会员: 随着联盟会员数量的不断增加,为加快联盟会员付款的进程、确保银行账户信息的安全性。我们将针对联盟用户的付款信息做相关升级,请联盟会员按照我们的提示规范自己的收款账户信息,以保 阅读更多…

道招网终于完成改版了

这个清明节放假三天,由于疫情还没有完全退去,大家还不太适合大规模聚集,更重要的是我本来也爱宅着不动。放假前就决定这三天干点正事,于是就想起把之前立的flag扶一下,把道招网的vue服务端渲染版彻底上 阅读更多…

黑莓官方催促twitter用户用回老版本客户端

鉴于许多黑莓用户的抱怨,黑莓现在在自己的应用市场推送最新的twitter客户端更新。如果你想修复twitter客户端的140字问题,那么你可能得用下面的方式来解决了:那就是回滚到twitter的上个 阅读更多…

微软针对windows7用户发布IE10

微软已经声明windows7用户终于可以享用IE10了,先前IE10是windows8用户独享的,但是去年11月份,微软公司WIIN7用户了一个ie10的预览版。但是从今天开始win7用户已经可以下载 阅读更多…

wordpress博客提示“Briefly unavailable for scheduled maintenance. Check back in a minute”

所谓“Briefly unavailable for scheduled maintenance. Check back in a minute”翻译过来就是“正在执行例行维护,请一分钟后回来”,这 阅读更多…

关注道招网公众帐号
联系博主