浏览器缓存机制详解(一)

浏览器缓存机制可以极大的提升用户体验,另一方面会因为读取缓存而展示了错误的东西,因而在开发中要设法将其删除。

什么是浏览器缓存?

浏览器缓存就是把一个已经请求过的web资源(如html页面,图片,JS,数据)拷贝一份放在浏览器中。缓存会根据进来的请求保存输入内容的副本。当下一个请求到来的时候,如果是相同的URL,浏览器会根据缓存机制决定是直接使用副本响应访问请求还是向源服务器再次发起请求。

使用缓存的原因

(1)减少网络带宽消耗
当web缓存副本被使用时,只会产生极小的网络流量,可以有效降低运营成本。
(2)降低服务器压力
给网络资源设定有效期之后,用户可以重复使用本地缓存,减少对源服务器的请求,简介降低了对服务器的压力,同时搜索引擎的爬虫机器人也能根据过期机制降低爬取的频率,也能有效降低服务器压力。
(3)减少网络延迟
缓存的使用可以明显加快页面打开速度,达到更好的用户体验。

浏览器的缓存机制

对于浏览器的缓存来讲,这些规则是在HTTP协议头部和HTML页面的Meta标签中定义的。他们分别从新鲜度和校验值两个维度来规定浏览器是否可以直接使用缓存中的副本,还是需要去源服务器获取新版本。

过期机制:指的是缓存副本的有效期。一个缓存的副本必须满足以下条件,浏览器会认为它是有效的,足够新的:
1.含有完整的过期时间控制头信息(HTTP协议报头),并且仍在有效期内
2.浏览器已经使用过这个缓存的副本,并且会在一个会话中已经检查过新鲜度(即服务器上的资源是否发生改变)
满足以上两种情况的一种,浏览器会直接从缓存中获取副本进行渲染

校验值(验证机制):服务器返回资源的时候有时在控制头信息带上这个资源的实体标签Etag(Entity Tag),它可以用来作为浏览器再次请求过程中的校验标识,如果发现校验标识不匹配,说明资源已经被修改或者过期,浏览器需要重新获取资源内容。

浏览器缓存的控制

(1)使用meta标签
Web开发者可以在HTML页面的节点中加入标签,代码如下:

<meta http-equiv="Pragma" content="no-cache">  
<!- Pragmahttp1.0版本中给客户端设定缓存方式之一,具体作用会在后面详细介绍 -->

上述代码的作用是告诉浏览器当前页面不被缓存,每次访问都需要去服务器上拉取。但是这种禁用缓存的形式很有限:
1.仅有IE才能识别这段meta标签的含义,其他主流浏览器仅识别”Cache-Control:no-store”的meta标签
2.在IE中识别到该meta标签的含义,并不一定会在请求字段中加上Pragma,但的确会让当前页面每次都发起新请求(仅限页面,页面上的资源则不受影响)

(2)使用缓存有关的HTTP消息报头
在HTTP请求和响应的消息报头中,常见与缓存有关的消息报头有:
这里写图片描述

这里写图片描述

不同字段间的比较:

Cache-Control和Expires

Cache-Control与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存中取数据还是重新发送请求到服务器取数据。只不过Cache-Control的选择更多,设置更细致,如果同时设置的话,优先级高于Expires。

Last-Modified/Etag与Cache-Control/Expires

在配置Last-Modified/Etag的情况下,浏览器再次访问统一的URI资源,还是会发送请求到服务器询问文件是否已经修改,如果没有,服务器只发送一个304给浏览器,告诉浏览器直接从自己的本地缓存取数据,如果修改过,那就将整个数据重新发送给浏览器。

Cache-Control/Expires则不同,如果检测到本地的缓存还在有效的时间范围内,浏览器直接使用本地副本,不会发送任何请求。两者一起使用的时候,Cache-Control/Expires的优先级要高于Last-Modified/Etag。即当当地副本根据Cache-Control/Expires发现还在有效期内,则不会再次发送请求去服务器询问修改时间(Last-Modified)或者实体标识符(Etag)了。
一般情况下,使用Cache-Control/Expires会配合Last-Modified/Etag一起使用,因为即使浏览器设置缓存时间,当用户点击“刷新”按钮时,浏览器会忽略缓存继续向服务器发送请求,这是Last-Modified/Etag将能够很好的利用304,从而减少响应开销。

浏览器向服务器请求资源的过程

这里写图片描述

关于缓存的两个概念

强缓存:
用户发送的请求,直接从客户端缓存中获取,不发送请求到服务器,不与服务器发生交互行为。
协商缓存:
用户发送请求,发送到服务器之后,由服务器判定是否从缓存中获取资源。
两者共同点:客户端获取的数据最后都是熊客户端的缓存中取得。
两者区别:从名字就可以看出,强缓存不与服务器发生交互,而协商缓存则需要需服务器发生交互。

获取资源具体过程详解:
(a)浏览器判定是否有缓存
“客户端缓存”就是指用户设备中的本地资源。不用浏览器缓存文件的地址不尽相同。浏览器判定是否有缓存的方式是通过浏览器读取本地缓存的地方(不同浏览器不同系统不同)看是否有对应的响应。(即查看文件是否存在)

(b)看缓存是否过期

客户端保留了一个response header
Date字段表明此时缓存服务器的时间。
Expires,Cache-Control
expires
Http1.0中的标准,表示过期时间,注意此处时间都是指的是服务器的时间。
由推片我们看到过期时间被设置为:Thu, 28 Sep 2017 06:38:37 GMT

Expires存在的问题是:该过期的时间是相对于服务器设定的,如果客户端时间和服务器端不一致(如用户重置了系统的时间)就会导致缓存跟期待的效果出现偏差。

Cache-Control:
Http1.1中的标准,可以看作为Expires的补充,使用的是相对时间的概念。
简单介绍一下Cache-Control的属性设置:
1.max-age:设置缓存的最大有效时间,单位为秒(s),max-age会覆盖Expires
2.s-maxage:只用于公用缓存,比如CDN缓存(s->share)。与max-age的区别是:max-age用于普通缓存,而s-maxage用于代理缓存。如果存在s-maxage会覆盖max-age和Expires
3.public:响应会被缓存,并且在用户间共享。默认是public
4.private:响应只作为私有的缓存,不能在用户间共享。如果需要HTTP认证,响应会自动设置为private。
5.no-cache:指定不缓存响应,表明资源不进行缓存。但是设置了no-cache之后不代表浏览器不缓存,而是在缓存前要向服务器确认资源是否被更改。因此有的时候只设置no-cache防止缓存就是不够保险,还可以加上private指令,将过期时间设置为过去的时间。
6.no-store:绝对禁止缓存
7.must-revalidate:如果页面过期,则去服务器进行获取
设置cache-control的规则如下图:
这里写图片描述

判断缓存是否过期的步骤:
1)查看是否有cache-control的max-age/s-maxage,如果有,则用服务器时间date值+max-age/s-maxage的秒数计算出新的过期时间,将当前时间与过期时间进行比较,判断是否过期
2)查看是否有cache-control的max-age/s-maxage,则用expires作为过期时间比较

上述过程执行完毕之后,如果判定未过期,则使用 客户端缓存,那么就属于强缓存

c)协商缓存:
协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问。
普通刷新会启用弱缓存,忽略强缓存。只有在地址栏或收藏夹输入网址、通过链接引用资源等情况下,浏览器才会启用强缓存,这也是为什么有时候我们更新一张图片、一个js文件,页面内容依然是旧的,但是直接浏览器访问那个图片或文件,看到的内容却是新的。
这个主要涉及到两组header字段:Etag和If-None-Match、Last-Modified和If-Modified-Since。

Etag

是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。
其原理如下:
当浏览器请求服务器的某项资源(A)时,服务器会根据A算出一个哈希值(3f80f-1b6-3e1cb03b)并通过Etag返回给浏览器,浏览器会把”3f80f-1b6-3e1cb03b”和A同时缓存至本地,当下次再次向服务器请求A时,会通过类似If-None-Match: “3f80f-1b6-3e1cb03b”的请求头把Etag发送给服务器,服务器再次计算A的哈希值和浏览器返回的值作比较,如果发现A发生变化就把A返回给浏览器(200),如果发现A没有变化就给浏览器返回一个304未修改。这样通过控制浏览器端的缓存,可以节省服务器的带宽,因为服务器不需要每次都把全部数据返回给客户端。

Etag和If-None-Match

Etag/If-None-Match返回的是一个校验码。Etag可以保证每一个资源都是唯一的,资源变化会导致ETag变化。服务器会根据浏览器上的If-None-Match来判断是否命中缓存。

与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于Etag重新生成过,response header中还会把这个ETag返回,即使这个Etag跟之前的没有变化。

Last-Modify/If-Modify-Since

浏览器第一次请求一个资源的时候,服务器返回的Header中会加上Last-Modify,Last-Modify是一个时间标识该资源的最后修改的时间,例如Last-Modify:Thu,31 Dec 2037 23:59:59 GMT。

当浏览器再次请求该资源时,request的请求头包含If-Modify-Since,该值缓存之前返回Last-Modify。服务器收到If-Modify-Since,根据资源的最后修改时间判断是否命中缓存。
如果命中缓存,则返回304,并且不会不会返回资源的内容,并且不会返回Last-Modify。
你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:

一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;

某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);

某些服务器不能精确的得到文件的最后修改时间。

Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

  • 24
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
浏览器的渲染机制可以分为以下几个步骤: 1. 构建 DOM 树:根据 HTML 文本构建 DOM 树,即将 HTML 文本解析成一个个的节点,然后将这些节点按照其在文档中的层级关系组成一棵树。 2. 构建 CSSOM 树:根据 CSS 文本构建 CSSOM 树,即将 CSS 文本解析成一个个的样式规则,然后将这些样式规则按照其在文档中的层级关系组成一棵树。 3. 合并生成渲染树:将 DOM 树和 CSSOM 树组合成渲染树(也称为呈现树或布局树)。渲染树只包含需要显示的节点和这些节点的样式信息。渲染树的构建过程中,浏览器会忽略掉那些不需要显示的节点,例如 head 标签、display:none 的节点等。 4. 计算布局信息:根据渲染树计算每个节点在屏幕上的位置和大小,这个过程被称为布局或排版(layout 或 reflow)。布局是一个相当昂贵的操作,因为浏览器需要遍历渲染树的每个节点,并根据节点的样式、大小、位置等信息计算其在屏幕上的位置和大小。 5. 绘制页面:根据渲染树和布局信息,将页面绘制到屏幕上,这个过程被称为绘制(painting 或 rasterization)。绘制的过程中,浏览器会将渲染树中每个节点的内容转换成位图,然后将这些位图组合成一张完整的页面。 6. 提交更新:将绘制好的页面提交到 GPU,由 GPU 将其显示到屏幕上。 以上是浏览器渲染机制的主要流程,其中布局(layout 或 reflow)是整个渲染过程中最耗时的步骤,因此在开发中需要尽可能减少布局的次数,以提高页面的性能表现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值