浏览器缓存

2,019 阅读7分钟

参考大佬的文章自己整理了一遍,原文链接:www.jianshu.com/p/54cc04190…

一. 为什么缓存

缓存是一种性能优化,可以缩短网络请求的时间,提高文件的重复利用率。

二. 缓存的位置

根据优先级从低到高排列,缓存的优先级分为一下几种:

  1. Service Worker
  2. Memory Cache
  3. Disk Cache
  4. Push Cache

1.Service Worker

首先,这种缓存位置有使用条件:传输协议使用HTTPS,是因为Service Worker涉及到请求拦截,需要使用HTTPS来保障安全。

Service Worker是运行在浏览器背后的独立线程,具体实现缓存分为三个步骤:

  1. 注册Service Worker,
  2. 监听到install事件后就可以缓存需要的文件,
  3. 下次访问时通过拦截请求的方式查询是否存在缓存,存在则读取缓存,否则请求数据

当上面的第三步没有命中缓存时,就需要调用fetch获取数据,这时候会根据缓存的优先级查找数据,但是不管是从其他缓存位置还是网络请求中获取到数据,浏览器都会显示是从ServiceWorker中获取到的内容。

特点:可以自由控制缓存哪些文件,如何匹配缓存,如何读取缓存,缓存是可持续性的。

2. Memory Cache

即内存中的缓存,主要包含页面中已经获取到的样式,脚本,图片等。

特点:读取高效,但是容量小,缓存持续性短,一旦关闭页面,内存重得缓存就会被释放。

以下Size列中显示memory cache的数据,都来自于内存缓存。


相关指令:preloader

注意点:使用内存缓存时,不关心HTTP缓存头部Cache-Control信息,资源匹配也不仅仅时对URL做匹配,还可能会对Content-type,CORS等其他特征做校验

3. Disk Cache

即存储在硬盘中的缓存,什么都能存在里面。

特点:可以容量大,但读取速度慢,最大的有点时存储的时效性(长时间不过期)。

相比于内存缓存,硬盘缓存会根据HTTP头部中的字段判断哪些资源需要缓存哪些可以直接使用那些需要重新请求。如果相同URL的资源一旦被硬盘缓存,就不会再去请求数据。(HTTP头部缓存信息在下一部分)

哪些文件丢在硬盘中,哪些丢在内存中?

  • 大文件,大概率存在硬盘中;小文件,大概率存在内存中
  • 当内存的使用率已经很高的时候,文件优先存在硬盘中

4. Push Cache

当以上三种缓存都没有被命中时,才会存在Push Cache中。

特点:只在Session中存在,一旦会话结束就被释放,缓存时间也很短暂(chrome 5min),同时也不会严格执行HTTP头中的缓存指令(和内存缓存有点像哈)

三. 缓存过程


  1. 浏览器每次发出请求,都会先去缓存中找请求结果缓存标识
  2. 浏览器每次拿到请求结果都会将结果缓存标识存到浏览器缓存中

根据是否需要向服务器重新发起HTTP请求,缓存的过程可以分为强缓存协议缓存

四. 强缓存

强缓存不会向服务器发送请求,直接从缓存中读取资源:

状态为200,Size为Memory Cache或Disk Cache的数据。


强缓存实现:

  1. Expires (HTTP Response Header)
  2. Cache-Control (HTTP Response/Request Header)

1.Expires (HTTP/1)

表示缓存的过期时间,是服务端具体时间点。

Expires = max-age + 请求时间(Date),需要和Last-Modified结合使用

缺点:

  • 只能精确到秒,如果在一秒内快速修改资源内容,是检查不出来变化的
  • 修改本地时间可能会造成缓存失效

2.Cache-Control (HTTP/1.1)

例子:Cache-Control:max-age=300  表示缓存的有效时间为30秒。


  • public 客户端和代理服务器都可以缓存
  • private 只有客户端可以缓存,代理服务器不可以缓存
  • no-cache 客户端缓存内容,不再使用Cache-Control的缓存控制方式做前置验证,使用Etag或者Last-Modified字段控制缓存,也就是转为了协议缓存
  • no-store 所有内容都不会被缓存,既不用强制缓存也不用协议缓存
  • max-age 值为时间,表示缓存在多少秒后失效,用于普通缓存
  • s-maxage 值也是时间,但是只在代理服务器中生效,用于代理缓存,优先级高于max-age,会忽略max-age和Expires
  • max-stale 能容忍的最大过期时间,表示客户端愿意接受一个过期了max-stale秒的响应,如果没有指定这个时间,不管资源过期了多久,浏览器都默认愿意接收。
  • min-fresh 能够容忍的最小新鲜度,表示客户端不愿意接收缓存时间超过min-fresh秒的响应。

3.Expires 和 Cache-Control对比

Cache-Control优先级高于Expires

五. 协商缓存

强缓存判断是否缓存是依据的时间段,不关心在这期间服务端文件是否被更新,可能导致加载的文件不是服务器最新的内容。为了知道服务器的内容是否被更新,需要使用协商缓存策略。

定义:在强制缓存失效之后,浏览器携带缓存标识符向服务器发送请求,由服务器根据缓存标识符决定是否使用缓存

协商缓存会有两种结果:

  1. 协商缓存生效,返回304 Not Modified
  2. 协商缓存失效,返回200和请求结果

通过两种HTTP Header实现:

  1. Last-Modified
  2. Etag

1.Last-Modified

浏览器在第一次请求某个资源,服务端返回资源的时候,在Response Header中会有Last-Modified信息,表示这个资源在服务器上的最后修改时间。浏览器接收后缓存数据文件,和Header;

浏览器下一次请求这个资源的时候,浏览器检测到有Last-Modified这个Header,将Last-Modified中的时间添加到If-Modified-Since这个Header中发出;

此时服务器接收到这个资源请求,会拿If-Modified-Since中的时间与服务器中这个资源的最后修改时间对比,没变化就返回304,最后修改时间比If-Modified-Since中的时间大,就说明有变化,返回200和新的资源文件。

缺点:

  • 本地打开缓存文件,即使没有修改,还是会造成Last-Modified被修改,服务端会认为资源更新了,导致发送相同的资源
  • Last-Modified只能以秒计时,一秒内修改多次,服务端感知不到,会返回304,不会返回新的资源(像Expires)

2.Etag

Etag是服务端响应请求的时候,返回的当前资源文件的一个唯一标识符(服务器生成),只要资源文件有变化,Etag就会重新生成;

浏览器在下一次请求资源时,会把上一次返回的Etag放在request Header的If-None-Match中,服务器比较If-None-Match与自己服务器中的Etag就知道要不要重新返回资源了。

3.两者对比

  • Etag精确度高
  • Last-Modified效率高,Etag的hash是需要根据文件内容计算的
  • Etag优先级高

六. 缓存机制

强缓存优先于协商缓存,强缓存生效的话,直接使用强缓存的资源,否则进行协商缓存,由服务器决定是否使用缓存。

如果什么缓存机制都没有设置,浏览器默认使用10%*(Date - Last-Modified)作为缓存时间。

七. 实际使用场景

1.频繁变化的资源

用协商缓存,使用Cache-Control: no-cache 使浏览器每次都请求服务器,可以显著减少响应数据的大小。

2.不常变化的资源

使用强缓存,将max-age设为一个很大的时间(比如一年),之后请求相同的URL就可以使用缓存的内容了,如果要解决文件更新了但是max-age没有到期的情况,就需要在URL上面添加hash,版本号等信息。

八. 用户行为对浏览器缓存的影响

1.正常重新加载

如果命中缓存,会直接使用缓存中的资源。

2.硬性重新加载

清除浅层的缓存,有一部分缓存还是在的。

2.清除缓存并重新加载

清除了所有的缓存,包裹本页面和其他页面,所有资源都重新获取。