缓存原因

  • 缓存可以减少用户等待时间,提升用户体验。直接从内存或磁盘中取缓存数据肯定是要比从服务器请求更快的;

减少网络带宽消耗。对于网站运营者和用户,带宽都代表着成本,过多的带宽消耗,意味着需要支付额外的费用。如果可以使用缓存,这样就只会产生极小的网络流量,这将有效地降低运营成本;

  • 降低服务器雅压力。给网络资源设定有效期之后,用户可以重读的使用本地的缓存,这样就减少了对服务器的请求,减少了服务器的压力;

缓存读写顺序

image.png

1.调用 Service Worker 的 fetch 事件获取资源;
2.查看 memory cache;
3.查看 disk cache;这里又细分:

  • 如果有强制缓存且未失效,则使用强制缓存,不请求服务器。这时的状态码全部是 200;
  • 如果有强制缓存但已失效,使用协商缓存,比较后确定 304 还是 200;

4.发送网络请求,等待网络响应;
5.把响应内容存入 disk cache (如果请求头信息配置可以存的话);
6.把响应内容的引用存入 memory cache (无视请求头信息的配置,除了 no-store 之外);
7.把响应内容存入 Service Worker 的 Cache Storage (如果 Service Worker 的脚本调用了 cache.put());
上面这一系列过程其实是浏览器查找缓存和把资源存入缓存的执行流程。

缓存位置

image.png
从浏览器开发者工具的 Network 面板下某个请求的 Size 中可以看到当前请求资源的大小以及来源,从这些来源我们就知道该资源到底是从 memory cache中读取的呢,还是从 disk cache 中读取的,亦或者是服务器返回的。而这些就是缓存位置:
浏览器缓存 - 图3

Service Worker

是一个注册在指定源和路径下的事件驱动 worker;特点是:

  • 运行在 worker 上下文,因此它不能访问 DOM;
  • 独立于主线程之外,不会造成阻塞;
  • 设计完全异步,所以同步 API(如 XHR 和 localStorage )不能在 Service Worker 中使用;
  • 最后处于安全考虑,必须在 HTTPS 环境下才可以使用;

说了这么多特点,那它和缓存有啥关系?其实它有一个功能就是离线缓存:Service Worker Cache;区别于浏览器内部的 memory cache 和 disk cache,它允许我们自己去操控缓存,具体操作过程可以参看 Using_Service_Workers;通过 Service Worker 设置的缓存会出现在浏览器开发者工具 Application 面板下的 Cache Storage 中。
memory cache
是浏览器内存中的缓存,相比于 disk cache 它的特点是读取速度快,但容量小,且时效性短,一旦浏览器 tab 页关闭,memory cache 就将被清空。memory cache 会自动缓存所有资源嘛?答案肯定是否定的,当 HTTP 头设置了 Cache-Control: no-store 的时候或者浏览器设置了 Disabled cache 就无法把资源存入内存了,其实也无法存入硬盘。当从 memory cache 中查找缓存的时候,不仅仅会去匹配资源的 URL,还会看其 Content-type 是否相同。
disk cache
也叫 HTTP cache 是存在硬盘中的缓存,根据 HTTP 头部的各类字段进行判定资源的缓存规则,比如是否可以缓存,什么时候过期,过期之后需要重新发起请求吗?相比于 memory cache 的 disk cache 拥有存储空间时间长等优点,网站中的绝大多数资源都是存在 disk cache 中的。

  • 浏览器如何判断一个资源是存入内存还是硬盘呢?关于这个问题,网上说法不一,不过比较靠谱的观点是:对于大文件大概率会存入硬盘中;当前系统内存使用率高的话,文件优先存入硬盘。

缓存按照缓存位置划分,其实还有一个 HTTP/2 的内容 push cache,由于目前国内对 HTTP/2 应用还不广泛,且网上对 push cache 的知识还不齐全,所以本篇不打算介绍这块,感兴趣的可以阅读这篇文章:HTTP/2 push is tougher than I thought

缓存顺序