看啥推荐读物
专栏名称: Iam_Bling
小小菜鸟,多多指教
目录
相关文章推荐
今天看啥  ›  专栏  ›  Iam_Bling

浏览器缓存方案

Iam_Bling  · 简书  ·  · 2018-12-26 00:02

HTTP响应头的实现

如果一个网站中的某个文件是百年不变的,那么肯定没有必要打开网页都重新获取啊。我们可以设置HTTP返回头的Cache-Control。

  • max-age=31536000:过期时间(单位是秒),最大不能超过一年,只要没过期或者手动清除缓存就会使用缓存。

  • no-cache:每次使用缓存之前,向服务器对资源进行验证。最终实现不使用缓存的过期资源的效果。(不要理解为字面意思:不缓存)

  • no-store:不使用缓存

  • must-revalidate:如果设置了max-age,在有效期内会使用缓存,否则就需要进行验证。所以可以结合使用Cache-Control: must-revalidate, max-age=60

那么服务端怎么进行验证呢?服务器第一次返回的响应头中有一个ETag字段,该字段相当于一个标识,具体的生成逻辑由服务端决定。
然后客户端之后的请求头中会携带一个If-None-Match字段,这个字段就是那个标识。服务器通过对比这个标识判断资源是否发生了更新。

Expires VS max-age

在响应头中有时还有一个expires字段,它和设置max-age一样都是设置有效期的。不过expires字段直接指定过期时间。而后者则是指定多长时间之后过期。

expires: Mon, 24 Dec 2018 13:55:24 GMT
last-modified VS Etag

在响应头中还有一个字段last-modified,它也可以用来做验证。那么它与Etag有什么区别呢?可以说Etag应该是更为精准的,last-modified最多精确到秒,而Etag则是只要发生变化,标识就会改变。

last-modified: Thu, 01 Jan 1970 00:00:00 GMT

Service Workers

1、Service Workers是什么?

Service Workers是浏览器在后台独立于网页运行的脚本,它可以支持离线体验。有以下几点注意事项:

  • 它是一种JavaScript 工作线程,不能直接访问DOM

  • 服务工作线程是一种可编程网络代理,让您能够控制页面所发送网络请求的处理方式。

  • 它在不用时会被中止,并在下次有需要时重启

  • 在开发过程中,可以通过 localhost 使用服务工作线程,但如果要在网站上部署服务工作线程,需要在服务器上设置 HTTPS。

2、生命周期
  1. 首先需要在我们的网页中注册Service Workers。注册会让浏览器后台执行Service Workers的安装步骤。

  2. 在Service Workers的独立脚本中,设置在安装过程中要缓存的文件,如果所有文件都缓存成功则安装成功;如果有任何一个失败都将失败,Service Workers就安装失败。

  3. 安装完成就该激活了,在这里我们对旧缓存进行管理。

  4. 激活之后,服务工作线程将会对其作用域内的所有页面实施控制

接下来,我们详细了解一下各个步骤的代码写法:

3、代码实现

在页面中注册Service Workers,来启动安装。在register方法中告诉浏览器Service Workers脚本的路径,这里是在根目录下,所以Service Workers接受该域下所有的fetch事件。

// 判断浏览器对Service Workers的支持情况
if ('serviceWprker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker
      .register('/sw.js')
      .then(registration => {
        if (registration.waiting) {
          console.log('安装完毕');
        }
      })
      .catch(err => {
        console.log(err);
      });
  });
}

接下来看一下Service Workers中的安装过程,这里会监听一个install事件,在事件回调中又可以分为三部:

var CACHE_NAME = 'my-cache';
var cacheList = ['/', '/src/main.js'];
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      return cache.addAll(cacheList);
    })
  );
});
  • 打开缓存,这里需要传入一个想要缓存的自定义名称。

  • 缓存文件,可以是一个由想要缓存的文件路径组成的数组

  • 确认所有需要的资产是否缓存,event.waitUntil() 方法带有 promise 参数并使用它来判断安装所花费的时间以及安装是否成功。

在安装完成之后,我们可能会想要一个对fetch事件的处理,当监听到fetch请求时,先匹配缓存中的内容,如果有就返回缓存的内容,没有则发起网络请求。

self.addEventListener('fetch', event => {
  event.respondWith(
    caches
      .match(event.request)
      .then(response => response || fetch(event.request))
  );
});

这里如果想要连续缓存新的请求,可以处理fetch请求的响应并将其添加到缓存中。

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(response => {
      if (response) {
        return response;
      }
      // 如果时新的请求就克隆一个请求
      var fetchRequest = event.request.clone();
      return fetch(fetchRequest).then(res => {
        // 校验响应,对第三方资产(type)的请求不会添加到缓存
        if (!res || res.status !== 200 || res.type !== 'basic') {
          return res;
        }
        // 该响应是Stream,所以主体只能用一次,需要克隆响应,一个发送给浏览器,一个保留在缓存中
        var responseToCache = res.clone();
        caches.open(CACHE_NAME).then(cache => {
          cache.put(event.request, responseToCache);
        });
        return res;
      });
    })
  );
});

接着看,当某个时候,Service Workers需要更新了,应该有以下步骤:

  • 在用户打开页面的时候浏览器会尝试在后台重新下载定义了Service Workers的脚本。如果有变化了就认为是更新了。

  • 这时新的Service Workers就会启动将触发install事件,此时此刻旧的Service Workers还在控制着页面,新的Service Workers处于waitting状态

  • 当前这个页面关闭之后,新的Service Workers就会占据控制权。

  • 新服务工作线程取得控制权后,就会触发其 activate 事件。

在 activate 回调中一般就是进行缓存管理,把旧的Service Workers清除掉。先定义一个新的缓存百名单,然后遍历Service Workers所有的缓存,把不在白名单内的删除。

self.addEventListener('activate', event => {
  // 白名单
  var cacheWhiteList = ['new-cache'];
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (cacheWhiteList.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});



原文地址:访问原文地址
快照地址: 访问文章快照