彻底理解浏览器的缓存机制

前言

在前端性能优化的方式中,最重要的当然是缓存了,使用好了缓存,对项目有很大的帮助。比如我们访问网页时,使用网页后退功能,会发现加载的非常快,体验感很好,这就是缓存的力量。

什么是缓存呢?

当我们第一次访问网站的时候,电脑会把网站上的图片和数据下载到电脑上,当我们再次访问该网站的时候,网站就会从电脑中直接加载出来,这就是缓存。

缓存有哪些好处?

  1. 缓解服务器压力,不用每次都去请求某些数据了。

  2. 提升性能,打开本地资源肯定会比请求服务器来的快。

  3. 减少带宽消耗,当我们使用缓存时,只会产生很小的网络消耗,至于为什么打开本地资源也会产生网络消耗,下面会有说明。

所谓浏览器缓存其实就是指在本地使用的计算机中开辟一个内存区,同时也开辟一个硬盘区作为数据传输的缓冲区,然后用这个缓冲区来暂时保存用户以前访问过的信息。

浏览器的缓存机制也就是我们说的HTTP缓存机制,其机制是根据HTTP报文的缓存标识进行的。


缓存过程分析

浏览器与服务器通信的方式为应答模式 ,即是:浏览器发起HTTP请求 -- 服务器响应该请求

那么浏览器第一次向服务器发起该请求后拿到请求结果,会根据响应报文中HTTP头的缓存标识,决定是否缓存结果。

是:则将请求结果和缓存标识存入浏览器缓存中,简单的过程如下图:

由上图我们可以知道:

  • 浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识;
  • 浏览器每次拿到返回的请求结果,都会将该结果和缓存标识存入·浏览器缓存中;

以上两点结论就是浏览器缓存机制的关键,他确保了每个请求的缓存存入与读取,只要我们再理解浏览器缓存的使用规则,那么所有的问题就迎刃而解了,本文也将围绕着这点进行详细分析。

为了方便大家理解,这里我们根据是否需要向服务器重新发起HTTP请求将缓存过程分为两个部分,分别是强制缓存协商缓存


强制缓存

强制缓存就是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程。

强制缓存的情况主要有以下三种:

  1. 不存在该缓存结果和缓存标识,强制缓存失效,则直接向服务器发起请求 (跟第一次发起请求一致),如下图:

  2. 存在该缓存结果和缓存标识,但该结果已失效,强制缓存失效,则使用协商缓存 (暂不分析),如下图

  3. 存在该缓存结果和缓存标识,且该结果尚未失效,强制缓存生效,直接返回该结果 ,如下图

.

强制缓存的缓存规则是什么?

当浏览器向服务器发起请求时,服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一起返回给浏览器。

控制强制缓存的字段分别是ExpiresCache-Control,其中Cache-Control优先级比Expires高。

.

Expires

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

到了HTTP/1.1,Expire已经被Cache-Control替代,原因在于Expires控制缓存的原理是使用客户端的时间与服务端返回的时间做对比,那么如果客户端与服务端的时间因为某些原因(例如时区不同;客户端和服务端有一方的时间不准确)发生误差,那么强制缓存则会直接失效,这样的话强制缓存的存在则毫无意义,那么Cache-Control又是如何控制的呢?

.

Cache-Control

在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存,当Cache-Control都存在时,Cache-Control优先级更高,主要取值为:

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

.

示例:

接下来,我们直接看一个例子,如下:

由上面的例子我们可以知道:

  • HTTP响应报文中expires的时间值,是一个绝对值
  • HTTP响应报文中Cache-Controlmax-age=600,是相对值

由于Cache-Control的优先级比expires,那么直接根据Cache-Control的值进行缓存,

意思就是说在600秒内再次发起该请求,则会直接使用缓存结果,强制缓存生效。

注:在无法确定客户端的时间是否与服务端的时间同步的情况下,Cache-Control相比于expires是更好的选择,所以同时存在时,只有Cache-Control生效。

.

缓存存放位置

上图状态码为灰色的请求则代表使用了强制缓存,请求对应的Size值则代表该缓存存放的位置 ,分别为 from memory cachefrom disk cache

  • from memory cache

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

  • from disk cache

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

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


协商缓存

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。

主要有以下两种情况:

  1. 协商缓存生效,返回304,如下

  2. 协商缓存失效,返回200和请求结果结果,如下

同样,协商缓存的标识也是在响应报文的HTTP头中和请求结果一起返回给浏览器的。

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

.

Last-Modified / If-Modified-Since

Last-Modified

是服务器响应请求时,返回该资源文件在服务器最后被修改的时间,如下:

If-Modified-Since

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

.

Etag / If-None-Match

Etag

是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),如下:

If-None-Match

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

注:Etag / If-None-Match优先级高于Last-Modified / If-Modified-Since,同时存在则只有Etag / If-None-Match生效。


总结

我们第一次进入页面,请求服务器,然后服务器进行应答,浏览器会根据response Header来判断是否对资源进行缓存,如果响应头中expires或者cache-control字段,代表这是强缓存,浏览器就会把资源缓存在memory cachedisk cache中。

第二次请求时,浏览器判断请求参数,如果符合强缓存条件就直接返回状态码200,从本地缓存中拿数据。

否则把响应参数存在request header请求头中,看是否符合协商缓存,符合则返回状态码304,不符合则服务器会返回全新资源。

强制缓存优先于协商缓存进行,若强制缓存(Expires和Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果,再存入浏览器缓存中;生效则返回304,继续使用缓存,主要过程如下:

  • 在 Header 内的字段用于控制缓存机制
  • 老方法 Expires,记录的绝对值
  • 新方法 Cache-Control 多了一堆选项,记录的时间是相对值
  • 获取缓存检测缓存是否过期,如果没过期取缓存,优先从内存,其次硬盘,如果过期,则与服务器协商缓存是否仍然可用,如果不可用则获取,可用取缓存

其他

缓存方案

目前的项目大多使用这种缓存方案的:

  1. HTML: 协商缓存;

  2. css、js、图片:强缓存,文件名带上hash。

.

强缓存与协商缓存的区别

  1. 强缓存不发请求到服务器,所以有时候资源更新了浏览器还不知道,但是协商缓存会发请求到服务器,所以资源是否更新,服务器肯定知道。

  2. 大部分web服务器都默认开启协商缓存。

.

刷新对于强缓存和协商缓存的影响

  1. 当ctrl+f5强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存。

  2. 当f5刷新网页时,跳过强缓存,但是会检查协商缓存。

  3. 浏览器地址栏中写入URL,回车 浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿。(最快)

相关推荐
Carlos_sam7 分钟前
OpenLayers:ol-wind之渲染风场图全解析
前端·javascript
拾光拾趣录17 分钟前
闭包:从“变量怎么还没死”到写出真正健壮的模块
前端·javascript
拾光拾趣录37 分钟前
for..in 和 Object.keys 的区别:从“遍历对象属性的坑”说起
前端·javascript
OpenTiny社区1 小时前
把 SearchBox 塞进项目,搜索转化率怒涨 400%?
前端·vue.js·github
编程猪猪侠1 小时前
Tailwind CSS 自定义工具类与主题配置指南
前端·css
qhd吴飞1 小时前
mybatis 差异更新法
java·前端·mybatis
YGY Webgis糕手之路2 小时前
OpenLayers 快速入门(九)Extent 介绍
前端·经验分享·笔记·vue·web
患得患失9492 小时前
【前端】【vueDevTools】使用 vueDevTools 插件并修改默认打开编辑器
前端·编辑器
ReturnTrue8682 小时前
Vue路由状态持久化方案,优雅实现记住表单历史搜索记录!
前端·vue.js
UncleKyrie2 小时前
一个浏览器插件帮你查看Figma设计稿代码图片和转码
前端