深入理解前端缓存(前端缓存)

深入理解前端缓存前端缓存是所有前端程序员在成长历程中必须要面临的问题,它会让我们的项目得到非常大的优化提升,同样也会带来一些其它方面的困扰。大部分前端程序员也了解一些缓存相关的知识,比如&#xff1

前端缓存是每个前端程序员成长过程中都要面对的问题,它在极大优化和改进你的项目的同时,也会带来其他问题。大多数前端程序员也有一些关于缓存的知识,比如强缓存、协商缓存、cookie,但我认为大多数前端程序员并不了解缓存机制。接下来我们将深入理解缓存机制和缓存时间公式,并讲解如何合理利用缓存机制来提高优化。我们将前端缓存分为两部分:HTTP 缓存和浏览器缓存。

HTTP 缓存

HTTP 是一种超文本传输协议,通常在TCP 上运行。从浏览器网络中可以看到,HTTP分为两部分:响应头(response headers)和请求头(request headers)。

以下标头字段与缓存相关。

expires

首先,让我们看一下MDN 过期日期的概述。

响应标头包含响应被视为过期的日期/时间。

注意:如果响应具有带有指令max-age 或s-maxage 的Cache-Control 标头,则将忽略Expires 标头。

过期时间: 2024 年4 月24 日星期三14:27:26 GMT

Cache-Control

Cache-Control是HTTP/1.1定义的缓存字段。可以以各种组合使用,例如max-age、s-maxage、公共/私有、无缓存/无存储。

Cache-Control: max-age=3600,s-maxage=3600,公共

max-age 相对于当前时间(以秒为单位)。如果设置了max-age,则过期时间将被覆盖,并且max-age 优先。

s-maxage 和max-age 之间的区别在于它仅适用于公共缓存服务器。例如,资源从源服务器发送,由中间代理服务器接收并缓存。

公共意味着该资源可以缓存在任何节点上,而私有意味着只能提供给客户端进行缓存。当设置为私有时,s-maxage 被禁用。

强缓存

强缓存的具体流程如下:

上面我们介绍了过期时间设置为根据客户端时间确定的绝对时间。如果资源缓存到其到期日期为2024 年4 月31 日,则到期日期将不准确。如果过期日期发生变化,则在访问资产时会重新请求服务器获取最新数据。

虽然max-age是一个相对时间,其值是以秒为单位的时间,但是max-age也会不准确。

那么,浏览器如何判断资源缓存是否有效呢?这里我们介绍一下资源新鲜度的计算公式。

我们以日常生活中食物的新鲜度为例。

食品是否新鲜=(生产日期+保质期)当前日期

那么你也可以用这个公式来判断缓存是否是新的。

缓存是否新建=(创建时间+ 过期时间|| max-age) 缓存年龄

这里的创建时间可以理解为服务器返回资源的时间,和过期一样是一个绝对时间。

缓存周期=响应周期+传输延迟时间+缓存驻留时间

响应寿命

有两种方法可以获取响应的年龄:

max(0, 响应时间- 日期时间) 年龄

responseTime:是指客户端收到响应的时间。

dateTime: 指服务器创建资源的时间。

Age:是响应头中的一个字段,通常以秒为单位。

传输延迟时间

传输延迟时间=客户端收到响应的时间-请求时间

停留时间

停留时间=当前客户端时间-客户端收到响应的时间

所以max-age 失败的问题是它也使用了客户端的时间。

协商缓存

协商缓存的具体流程如下:

如上所示,协商缓存由两个字段决定:Etag 和Last-Modified。那么Etag标志是如何生成的呢?

可以在Node中查看etag第三方库。

该库使用isState 方法来确定文件的格式。对于文件格式,请使用第一种方法,该方法根据文件内容和修改时间生成Etag。

第二种方法:根据文件内容、哈希值、内容长度生成Etag。

浏览器缓存

如果您访问掘金网站并查看您的网络,您会看到有一个“大小”列,有些列没有大小,但被标记为“磁盘缓存”、“内存缓存”等。

内存缓存翻译,顾名思义,是保存在内存中的,所以可以看到时间一栏是0ms。虽然缓存被清除,但是内存大小非常有限,所以如果要存储大量资源,还是应该使用磁盘缓存。

磁盘缓存是一种存储在计算机磁盘上的缓存,与内存缓存相反,这意味着读取时间更长。 1 毫秒。

缓存获取顺序

浏览器首先搜索内存缓存,如果内存缓存不存在,则再搜索回磁盘缓存。磁盘缓存中的资源。如果磁盘缓存不存在,则发出网络请求,并将最新资源存储到内存或磁盘缓存中。

缓存存储优先级

浏览器如何决定将资源存储在内存缓存还是磁盘缓存中?

当您打开掘金网站时,您会看到除了从内存中检索的Base64 图像之外,大多数其他资源都是从磁盘中检索的。

js 文件,你需要小心。可以看到下面的js文件有的缓存到磁盘,有的缓存到内存。为什么是这样?

启动器列指示资源的加载位置。如果单击某列从内存中检索资源,您将看到该资源在HTML 渲染阶段加载。包括以下代码。

!DOCTYPE html

html lang=\’en\’

元字符集=\’UTF-8\’/

标题文档/标题

脚本src=\’https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js\’/script

/头

身体

像div id=\’root\’这样加载的js资源更有可能存储在内存/div中。

/身体

/html

内存放弃的是异步资源,不会缓存在内存中。

上图中,可以看到initiator列的值为(index):50,但它仍然缓存在内存中,所以可以点击查看代码如下。

这个js文件是通过动态创建script标签来动态部署的。

Preload 与 Prefetch

预加载和预取也会影响浏览器缓存资源的加载。

预加载称为预加载,用在链接标签中,指在页面加载后、渲染机制干预之前立即需要哪些资源。

链接rel=\’预加载\’ href=\’//lf3-cdn-tos.bytescm.com/obj/static/xitu_juejin_web/0358ea0.js\’ as=\’script\’

当你使用preload来预加载资源时,这些资源总是从磁盘缓存中读取。

prefetch的意思是预取,浏览器利用空闲时间下载资源并存储到缓存中。

链接rel=\’prefretch\’ href=\’//lf3-cdn-tos.bytescm.com/obj/static/xitu_juejin_web/0358ea0.js\’

使用预取加载的资源可能会在您更新页面时从磁盘缓存中读取,并且当您跳转到使用它的页面时,该资源将直接从磁盘加载。

使用no-store 意味着资源不被缓存。使用no-cache 意味着告诉(代理)服务器不要直接使用缓存,而是在响应标头中返回时向源服务器发起请求。这意味着客户端可以缓存资源,但必须缓存它。服务器在使用缓存资源之前验证其有效性,这对于需要在每次访问时进行身份验证的应用程序非常有用。

当然,您也可以在代码中添加元标记来修改资源的请求标头。

meta http-equiv=\’缓存控制\’ content=\’no-cache\’ /

示例

到这里我们就启动了nestjs服务。 getdata接口缓存10秒。这是代码:

@Get(\’/getdata\’)

getData(@Response() res: Res) {

return res.set({ \’过期\’: new Date(Date.now() + 10).toUTCString() }).json({

list: new Array(1000000).fill(1).map((item,index)=({index,item:\’index\’+index}))

});我

}

第一个请求花费了334 毫秒。

第二个请求花费了163 毫秒,因为它使用了磁盘缓存,使其速度提高了近50%。

接下来看看是否可以使用Cache-Control来覆盖Exprie。修改getdata接口如下,将Cache-Control设置为1s。如果刷新页面,就会看到getdata接口没有被缓存,每次都会向服务器发送请求。

@Get(\’/getdata\’)

getData(@Response() res: Res) {

return res.set({ \’Expires\’: new Date(Date.now() + 10).toUTCString(), \’Cache-Control\’: 1 }).json({

list: new Array(1000000).fill(1).map((item,index)=({index,item:\’index\’+index}))

});

}

细心的同学应该注意到,清除缓存后第一次和第二次请求的大小是不同的。为什么是这样?

右键F12打开刷新按钮,点击“清除缓存并硬重新加载”。

打开大请求行可以更轻松地查看大小。勾选后,Size下会出现两行,第一行是请求内容的大小,第二行是实际大小。

刷新后,你会看到大小变成了283B。

带着这个问题,让我们仔细看看浏览器压缩。 HTTP2和HTTP3的压缩算法几乎相同。我们来看看HTTP2(HPACK)压缩算法。

HTTP2 HPACK压缩算法

HPACK压缩算法大致分为静态哈夫曼(Huffman)压缩和动态哈夫曼压缩。所谓静态压缩是指根据HTTP提供的静态字典表查找对应的请求头字段并存储对应的索引值。显着减少内部压力空间。

动态压缩是在同一会话级别执行的,其中第一个请求的响应包含类似{list: [1, 2, 3]} 的消息,并且其他后续请求的响应也存储在该表中。仅返回该表头在动态表中的索引以达到压缩目的。

如果您想了解更多关于霍夫曼算法的原理,请访问并阅读此博客。

Last-Modified 与 If-Modified-Since

Last-Modified表示属于响应头字段的资源的最后修改时间。当浏览器第一次收到从服务器返回的资源的Last-Modified 值时,它会保存该值,并在下次访问该资源时使用If-Modified-Since 请求标头将其发送到服务器。检查资源是否过期。

亚穆尔

复制代码

最后修改时间: 2021 年5 月14 日星期五17:23:13 GMT

If-Modified-Since: 2021 年5 月14 日星期五17:23:13 GMT

如果资源在If-Modified-Since 字段中指定的时间内尚未更新,服务器将使用状态代码304 Not Modified 进行响应。

Etag 与 If-None-Match

Etag代码是资源的唯一标识符。同样,浏览器第一次收到服务器返回的Etag值后,访问时会持有If-None。下次向服务器发送Match请求头来检查资源是否过期。

Etag:\’29322-09SpAhH3nXWd8KIVqB10hSSz66\’

如果-无-匹配:\’29322-09SpAhH3nXWd8KIVqB10hSSz66\’

如果两者不相同,则说明服务器资源已更新,服务器返回该资源最新的Etag值。

#以上详细了解前端缓存的相关内容来源网络,仅供参考。相关信息请参见官方公告。

原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/91214.html

(0)
CSDN's avatarCSDN
上一篇 2024年6月21日 下午6:50
下一篇 2024年6月21日 下午6:50

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注