使用传统前端技术增强客户端缓存能力

栏目: 前端 · 发布时间: 6年前

内容简介:前几天重构之后,Lighthouse 中有一个评分让我念念不忘:说到

前几天重构之后,Lighthouse 中有一个评分让我念念不忘: Progressive Web App

PWA 不算一个新话题了,所以概念性的东西和 API 我就不多做介绍,下面简单介绍一个无干预更新的缓存方案,整体代码量在一百行以内,如果你也想在不“大动干戈”的情况下对站点或者 Web App 进行性能提升的话,可以了解一下。

浏览器客户端代码

说到 PWA ,我们能直接想到的,无非是 增强缓存推送能力 。而这两个能力,都是 ServiceWorker API 实现的。(添加桌面图标这个需求,我不需要,就不介绍了,感兴趣可以自行搜索)

我在之前的重构文章中有简单聊过访客数据,其中有一部分访客使用的客户端并不支持 Service Worker ,所以在使用它的时候,需要使用 能力探测 的方式引入,比如:

try {
  ('serviceWorker' in navigator) && navigator.serviceWorker.register('/sw.js');
} catch (error) {
  console.error(error);
}

当然,构建压缩之后,你得到的结果应该是 drop console 的最简代码。不过,如果你不确定你的运行环境是否有问题,可以使用下面带有调试日志的版本。

try {
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.min.js').then(function(registration) {
      console.log('ServiceWorker registration successful with scope: ', registration.scope);
    }).catch(function(err) {
      console.error('ServiceWorker registration failed: ', err);
    });
  }
} catch (error) {
  console.error(error);
}

ServiceWorker 客户端代码

上面介绍浏览器客户端代码的时候,有引入一个外部脚本依赖 sw.js

在分享代码之前,有做过 PWA 相关项目或者了解的同学,可能或多或少会在 增强缓存 这个地方被坑到,比如:缓存无法更新、缓存内容过多无法写入。

缓存无法更新有一个简单有效的解决方案:定时切换缓存使用的 Store 。如果再引入 当前时间 这个因素,可以保障缓存使用的 Store 不存在资源争抢的问题。

结合站点内容特点,配合定期清理缓存的脚本,可以将缓存数量控制在一定的范围之内。

这里提供一个小思路,对服务端资源进行二次缓存的时候,可以设定一个最大缓存时间的策略,而这里有两个方案:

TTL
TTL

我个人选择第二个方案,牺牲一定的缓存复用,但是有效降低资源之间的版本管理的复杂度。

而需要缓存的资源一般分为两类:

  • 短时间缓存:页面或者页面片段
  • 相对长时间缓存:图片等媒体资源,或者有一定跨页面通用能力的脚本和样式资源

这里以10分钟(调试模式单位替换为秒)为一个时间段,为短时间缓存的资源进行缓存。设定星期数为其他资源进行缓存周期。

这里我们不必过分处理 installactive 事件,只需要统一在 fetch 事件中进行缓存更新和清理即可,比如下面这样:

function weekId() {
  var now = (new Date());
  var dt = new Date(now.getFullYear(), 0, 1);
  return Math.ceil((((now - dt) / 86400000) + dt.getDay() + 1) / 7);
}
 
var isDevMode = false;
var CACHE_LONG_TTL = 'WEEK_' + weekId();
var CACHE_TINY_TTL = 'TINY_';
 
function cleanCache(whiteList) {
  return caches.keys().then(function(buckets) {
    return Promise.all(buckets.filter(function(bucket) {
      return whiteList.indexOf(bucket) === -1;
    }).map(function(bucket) {
      return caches.delete(bucket);
    }));
  });
}
 
self.addEventListener('activate', function(event) {
  event.waitUntil(cleanCache([CACHE_LONG_TTL]));
});
 
self.addEventListener('fetch', function(event) {
 
  var url = new URL(event.request.url);
  if (url.protocol.toLowerCase() !== 'https:') return;
 
  var now = new Date;
  var CACHE_INTERVAL = Math.floor((isDevMode ? now.getSeconds() : now.getMinutes()) / 10);
  var CACHE_KEY = CACHE_TINY_TTL + CACHE_INTERVAL;
 
  if (url.pathname.endsWith('/') ||
      url.pathname.endsWith('.html') ||
      url.pathname.endsWith('.md') ||
      url.pathname.endsWith('/feed/') ||
      url.pathname.endsWith('/feed') ||
      url.pathname.endsWith('sw.js')) {
 
    cleanCache([CACHE_LONG_TTL, CACHE_KEY]);
 
    event.respondWith(caches.open(CACHE_KEY).then(function(cache) {
      return cache.match(url).then(function(response) {
        if (response) return response;
        return fetch(event.request).then(function(response) {
          cache.put(event.request, response.clone());
          return response;
        });
      });
    }));
 
  } else {
    event.respondWith(caches.open(CACHE_LONG_TTL).then(function(cache) {
      return cache.match(event.request).then(function(response) {
        if (response) return response;
        return fetch(event.request).then(function(response) {
          cache.put(event.request, response.clone());
          return response;
        });
      });
    }));
  }
 
});

如果你的访客有不少是 Chrome v50FireFox v46 以下的客户端,那么你可能还需要引入下面的 Polyfill : https://github.com/dominiccooney/cache-polyfill/blob/master/index.js

当然,在引入的时候,建议还是进行压缩,进一步提高页面性能(哪怕它是独立于客户端脚本另外的异步进程)。

当一切都完成之后,如果顺利的话,你的网站的将支持有限时间(本文是10min)的离线访问,以及重复访问时更好的响应能力。

另外,你也不需要担心 sw.js 被缓存后,这个站点变成“完全离线”。因为 sw.js 按照规范可以保证它的最长存在生命周期是 1天,也就是说,未来你的策略更新最多延迟1天。

最后

使用传统前端技术增强客户端缓存能力

再次跑分,发现 Lighthouse 已经全面绿色评价了,不过前文中我提过,我不太需要把网站变为纯粹的 PWA 应用,没有去设定 mainfest ,所以,依旧有 4 点改进建议。

  1. 用户不能够“安装” Web App。
  2. 没有定义启动屏幕(仿客户端体验)。
  3. 没有定义顶栏的主题色。
  4. viewport 没有优化。

这些后面再说吧。

— EOF


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Writing Apache Modules with Perl and C

Writing Apache Modules with Perl and C

Lincoln Stein、Doug MacEachern / O'Reilly Media, Inc. / 1999-03 / USD 39.95

Apache is the most popular Web server on the Internet because it is free, reliable, and extensible. The availability of the source code and the modular design of Apache makes it possible to extend Web......一起来看看 《Writing Apache Modules with Perl and C》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具