浏览器缓存总结篇

浏览器缓存策略大家一定不陌生,如果没有进行系统的归纳总结,可能三言两语说不清楚。这点我在面试中感触颇深,以前未经过深入理解时,只能说出几个概念或者回答得比较模糊,甚至说错,显得自己的基础知识特别不扎实。

  1. 浏览器缓存介绍
  2. 缓存机制(原理)
  3. 缓存分类
  4. 缓存位置

下面是我做的一个大致的思维导图:
在这里插入图片描述

1.浏览器缓存介绍

浏览器缓存就是把一个请求过的资源(如图片、css、js等)储存在本地。当下次发送请求时,如果是相同的 URL,浏览器会根据缓存机制决定是直接使用缓存资源,还是重新向服务器再次发送请求获取资源。

2.缓存机制(原理)
  1. 浏览器发送请求前,根据请求头的 Expires 和 Cache-Control 判断是否命中强缓存策略(包括是否过期),如果命中,直接从缓存获取资源,不会再请求服务器。
  2. 没有命中强缓存规则,浏览器会发送请求,根据请求头的 Last-Modified 和 Etag 判断是否命中协商缓存,如果命中,直接从缓存获取资源。
  3. 如果前两步都没有命中,则直接从服务器获取资源。
3.缓存分类
  1. 强缓存

强缓存是指,浏览器不会像服务器发送请求,而是直接从本地缓存中读取内容。

与其相关的响应头是 ExpiresCache-Control

Expires
它是响应头字段,用来设置资源的过期时间,浏览器通过将其与当前本地时间对比,判断资源是否过期,在此时间之后则过期。
它的值是GMT格式的标准时间,如:

Expires: Sun, 20 Jun 2021 02:19:39 GMT

注意:Expires 是服务器下发的绝对时间 ,无法保证客户端与服务器时间的一致性。原因一是本地时间本来就可能与服务器时间有偏差,二是如果用户修改了本地系统的时间也会导致偏差。所以 Expires 是有缺陷的。

Cache-Control
它是通用消息头字段,被用在http请求和响应中,通过设置指定指令实现缓存机制。其中,最重要的指令是 “max-age=<seconds>”。同样地,它也是用来设置资源的过期时间。

Cache-Control: max-age=31536000 // 设置了一年后过期

注意:相对 Expires 而言,max-age 设置的是相对时间,是距离发起请求的时间的秒数。无论本机与服务器时间是否一致,最后以相对时间为准;在此时间内不会再去请求服务器,直接去浏览器拿缓存。

Cache-Control 常见值有:(完整的列表可以查看:MDN

  • Cache-Control: max-age=<seconds> // 设置缓存周期,超过这个时间缓存被认为过期(单位秒)
  • Cache-control: no-cache // 虽然字面意思是“不要缓存”,但实际上是可以存储在缓存区的,只不过要通过服务器验证后才可使用缓存
  • Cache-control: no-store // 不使用任何缓存,真正的不缓存数据到本地

Expires 是 HTTP/1.0 协议中的。 为了解决 Expires 的缺陷, HTTP/1.1 中新增了Cache-Control 来定义缓存过期时间。

自从 HTTP/1.1 开始,Expires 逐渐被 Cache-control 取代。两者同时存在的话,Cache-control 的优先级高于 Expires,Expires 的存在只是为了兼容 HTTP/1.0。所以为了兼容 HTTP/1.0 和 HTTP/1.1,实际项目中两个字段我们都会设置。

顺便提一下,HTTP/1.0 还有一个功能比较弱的缓存控制机制:Pragma。请求中包含 Pragma 的效果跟在头信息中定义 Cache-Control: no-cache 是相同的。使用 Pragma 时将忽略 Expires 和 Cache-Control 头,通常定义 Pragma 是为了向后兼容基于HTTP/1.0的客户端。

  1. 协商缓存

协商缓存是指,在强缓存失效后,浏览器会先请求一下服务器询问该缓存是否可用,可用则直接使用该缓存,不可用则重新向服务器发送请求。

与其相关的响应头是 Last-ModifiedIf-Modified-SinceEtagIf-None-Match

Last-Modified
浏览器第一次请求资源时,服务器返回资源的同时,会在响应头中添加 Last-Modified 字段,写明资源最后一次被修改的时间。浏览器将这个值和内容一起记录在缓存数据库中。

Last-Modified: Fri, 23 Oct 2020 10:49:15 GMT

If-Modified-Since
浏览器再次请求这个资源时,会在请求头中将上次的 Last-Modified 的值写入到请求头的 If-Modified-Since 字段中。

接下来,服务器会将 If-Modified-Since 的值与 Last-Modified 字段进行对比。如果相等,则表示未修改,响应 304 状态码;如果 If-Modified-Since 的时间小于服务器中这个资源的最后修改时间,则表示修改了,响应 200 状态码,并返回最新数据。

但是 Last-Modified/If-Modified-Since 还是有缺陷

  • 时间只能精确到秒,如果资源在一秒内进行了多次修改,则无法识别,还会去读缓存导致不能返回正确资源
  • 只要资源被改变(如 靠服务器动态生成),就会改变 Last-Modified 的值,虽然实质内容并没有改变,也会重新返回资源,这样就没起到缓存的作用

既然根据文件修改时间来决定是否缓存存在缺陷,为了解决这些缺陷,所以在 HTTP/1.1 增加了 ETagIf-None-Match,直接根据文件内容是否修改来决定是否缓存。

Etag
响应头字段,是资源的特定版本的标识符。Etag 是由服务端生成的(一般采用 hash 算法生成),只要资源有变化,Etag就会重新生成。服务器返回资源的同时,会在响应头中添加该字段,浏览器会将 Etag 与资源缓存。

If-None-Match
浏览器再次请求这个资源时,会在请求头中将上次的 Etag 的值写入到请求头的 If-None-Match 字段中。
接下来,服务器会将 If-None-Match 的值与服务器上该资源的 Etag 字段进行对比。如果一致,则表示未修改,响应 304 状态码;如果匹配不上,响应 200 状态码,并返回最新数据。
(看出来了吗,流程其实跟 Last-Modified/If-Modified-Since 是一样的,只是使用的字段不一样而已)

etag:W/“cd86460562d990d7cd0aad77a850203d”
if-none-match:W/“cd86460562d990d7cd0aad77a850203d”

说了这么多,你可能会问,缓存的资源存在哪里呢?那么请继续看叭~

4.缓存位置

我们打开 CSDN 首页来看看,在 Chrome 的开发工具中,Network->Size 列可以看到请求的最终处理方式。

第一次发送请求后,Size 列显示的都是资源大小:

在这里插入图片描述
再次发送请求,Size 列显示的值就出现了变化。可以看到 有的是 memory cache,有的是 disk cache:

在这里插入图片描述
其实,Size 列主要有 4 种情况:
1. 资源的大小:表示进行了网络请求
2. memory cache:表示来自内存中的缓存。
3. disk cache:表示来自硬盘上的缓存。(先读内存再读硬盘)
4. ServiceWorker:取自 ServiceWorker 的缓存。(以后专门写一篇)

缓存读取顺序:(Service Worker -> memory cache -> disk cache)
1. 当有Service Worker时,浏览器会从 Service Worker 读取缓存
2. 再去内存读取缓存,如果有,直接加载
3. 如果内存没有,则从硬盘读取,如果有直接加载
4. 如果硬盘也没有,那么就进行网络请求
5. 获取到的资源缓存到硬盘和内存

还有最后一个问题,浏览器会把哪些资源放入内存,哪些资源放入硬盘呢?我看了好多篇文章,都没有一个统一或准确的说法。路过的大佬有了解的一定留下宝贵的评论奥~!!

这篇文章花了我两三天时间整理出来的,有误之处欢迎在评论中指出,先在这里谢过啦!!~
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值