聊一聊浏览器缓存

缓存的概念

什么是缓存

In computing, a cache is a hardware or software component that stores data so future requests for that data can be served faster.

cache 是一个硬件或软件的组件,用来存储将来会请求到的数据,让数据获取更快。狭义上,cache 指介于 CPU 和内存之间存储介质。广义上,凡是位于速度相差较大的两种硬件之间,用于协调两者数据传输速度差异的结构,均可称之为 cache。

缓存可分为硬件缓存和软件缓存两类。

  • 硬件 cache:CPU cache,GPU cache,DSP;
  • 软件 cache:Disk Cache,Web Cache 等。

两者主要区别在于,硬件缓存完全由硬件管理,而软件缓存是由软件来管理的。这里我们主要讨论软件缓存中的 Web Cache。

Web 缓存是一项临时存储 Web 资源的技术,以减少服务器负载。

Web 页面为什么要有缓存?

  1. 缓解服务器压力
  2. 提升性能
  3. 减少带宽消耗

Web 缓存的分类

  • 浏览器缓存: 针对单个用户
  • 代理缓存
  • 网关缓存:CDN
  • 数据库缓存
    数据库缓存是为了减少数据库查询,数据库缓存的数据都基本都存储在内存中。

浏览器缓存

计算机科学领域只有两个难题,缓存失效和命名。 —— Phil Karlton

浏览器的缓存策略

缓存的目标

  • 一个检索请求的成功响应: 对于 GET请求,响应状态码为:200,则表示为成功。一个包含例如HTML文档,图片,或者文件的响应;
  • 不变的重定向: 响应状态码:301;
  • 可用缓存响应:响应状态码:304,这个存在疑问,Chrome会缓存304中的缓存设置,Firefox;
  • 错误响应: 响应状态码:404 的一个页面;
  • 不完全的响应: 响应状态码 206,只返回局部的信息;
  • 除了 GET 请求外,如果匹配到作为一个已被定义的cache键名的响应;

浏览器对于缓存的处理是根据第一次请求资源时返回的响应头来确定的。

强缓存

强缓存就是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程。控制强制缓存的字段分别是 Expires 和 Cache-Control,其中 Cache-Control 优先级比 Expires 高。

Expires
Expires 是 HTTP/1.0 控制网页缓存的字段,其值为服务器返回该请求结果缓存的到期的绝对时间,即再次发起该请求时,如果客户端的时间小于 Expires 的值时,直接使用缓存结果。

Cache-Control
在 HTTP/1.1 中,Cache-Control 是最重要的规则,主要用于控制网页缓存,主要取值为:

  • public:所有内容都将被缓存(客户端和代理服务器都可缓存)
  • private:所有内容只有客户端可以缓存,Cache-Control的默认取值
  • no-cache:可以使用缓存内容,但是每次是否使用缓存,需要经过协商缓存来验证决定
  • no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
  • max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效

from memory cache代表使用内存中的缓存,from disk cache则代表使用的是硬盘中的缓存,浏览器读取缓存的顺序为memory –> disk。

内存缓存(from memory cache)
内存缓存具有两个特点,分别是快速读取和时效性:

  1. 快速读取:内存缓存会将编译解析后的文件,直接存入该进程的内存中,占据该进程一定的内存资源,以方便下次运行使用时的快速读取。
  2. 时效性:一旦该进程关闭,则该进程的内存则会清空。

硬盘缓存(from disk cache)
硬盘缓存则是直接将缓存写入硬盘文件中,读取缓存需要对该缓存存放的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢。

在浏览器中,浏览器会在js和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。内存缓存和磁盘缓存都只能用于派生类的资源请求。

协商缓存

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。协商缓存是无法减少请求数的开销的,但是可以减少返回的正文大小。主要有以下两种情况:

协商缓存生效,返回304
协商缓存失效,返回200和请求结果结果

控制协商缓存的字段分别有:Last-Modified/If-Modified-Since 和 Etag/If-None-Match,其中 Etag/If-None-Match 的优先级比 Last-Modified/If-Modified-Since 高。

Last-Modified / If-Modified-Since
Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间,如下。
f78610c56fac74d69ea5bea30ff4ce8f.png
If-Modified-Since则是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。服务器收到该请求,发现请求头含有If-Modified-Since字段,则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件,如下。

Etag/If-None-Match
Etag 是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),如下。
1751531d0244181a16d8d01a27be7b1a.png
ETag的值有可能包含一个 W/ 前缀,来提示应该采用弱比较算法。

If-None-Match 是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。服务器收到该请求后,发现该请求头中含有If-None-Match,则会根据If-None-Match的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200,如下。

启发式缓存

ae5076aeb2713256708f6389fbee55d1.png

f15c74ca21c152411b97997fd6607287.png
浏览器用来确定缓存过期时间的字段一个都没有!那该怎么办?有人可能会说下次请求直接进入协商缓存阶段,携带If-Moified-Since呗,不是的,浏览器还有个启发式缓存阶段😎
根据响应头中2个时间字段 Date 和 Last-Modified 之间的时间差值,取其值的10%作为缓存时间周期。

用户操作行为对缓存的影响

0ddeed8a00c722ce4fbd9b08f0985b87.png