资讯专栏INFORMATION COLUMN

从前端角度理解缓存

Astrian / 1255人阅读

摘要:缓存的概念分很多种,本次讨论的主要就是前端缓存中的缓存。从字面理解,强制缓存的方式简单粗暴,给设置了过期时间,超过这个时间之后过期需要重新请求。这个方法简单直接,直接设定一个绝对的时间当前时间缓存时间。然后从缓存中读取数据。

缓存的概念分很多种,本次讨论的主要就是前端缓存中的Http缓存。

缓存是怎么回事

前端发送请求主要经历以下三个过程,请求->处理->响应。
如果有多次请求就需要重复执行这个过程。

重复请求的过程

以下是一个重复请求的流程图:

从以上的流程图可以看书,如果用户重复请求同一资源的话,会对服务器资源造成浪费,服务器重复读取资源,发送给浏览器后浏览器重复下载,造成不必要的等待与消耗。

缓存读取的过程

缓存读取就是浏览器在向服务器请求资源之前,先查询一下本地缓存中是否存在需要的资源,如果存在,那便优先从缓存中读取。当缓存不存在或者过期,再向服务器发送请求。

如何开启Http缓存并对缓存进行设置,是本次讨论的关键。

缓存的类型

浏览器有如下常见的几个字段:

expires: 设置缓存过期的时间

private: 客户端可以缓存

public: 客户端和代理服务器都可缓存

max-age=xxx: 缓存的内容将在 xxx 秒后失效

no-cache: 需要使用对比缓存来验证缓存数据

no-store: 所有内容都不会缓存,强制缓存,对比缓存都不会触发

last-modified: 内容上次被修改的时间

Etag: 文件的特殊标识

强制缓存和协商缓存

缓存方法可以分为强制缓存与协商缓存。

从字面理解,强制缓存的方式简单粗暴,给cache设置了过期时间,超过这个时间之后cache过期需要重新请求。上述字段中的expirescache-control中的max-age都属于强制缓存。

协商缓存根据一系列条件来判断是否可以使用缓存。

强制缓存优先级高于协商缓存

强制缓存 expires

expires给浏览器设置了一个绝对时间,当浏览器时间超过这个绝对时间之后,重新向服务器发送请求。

Expires: Fri, 04 Jan 2019 12:00:00 GMT

这个方法简单直接,直接设定一个绝对的时间 (当前时间+缓存时间)。但是也存在隐患,例如浏览器当前时间是可以进行更改的,更改之后expires设置的绝对时间相对不准确,cache可能会出现长久不过期或者很快就过期的情况。

cache-control: max-age

为了解决expires存在的问题,Http1.1版本中提出了cache-control: max-age,该字段与expires的缓存思路相同,都是设置了一个过期时间,不同的是max-age设置的是相对缓存时间开始往后多久,因此不存在受日期不准确情况的影响。

但是强制缓存存在一个问题,该缓存方式优先级高,如果在过期时间内缓存的资源在服务器上更新了,客服端不能及时获取最新的资源。

协商缓存

协商缓存解决了无法及时获取更新资源的问题。以下两组字段,都可以对资源做标识,由服务器做分析,如果未进行更新,那返回304状态码,从缓存中读取资源,否则重新请求资源。

last-modify

last-modify告知了客户端上次修改该资源的时间,

Last-Modified: Wed, 02 Jan 2019 03:06:03 GMT

浏览器将这个值记录在if-modify-since中(浏览器自动记录了该字段信息),下一次请求相同资源时,与服务器返回的last-modify进行比对,如果相等,则表示未修改,响应 304;反之,则表示修改了,响应 200 状态码,并返回数据。

last-modify以秒为单位进行更新,如果小于该单位高频进行更新的话,不适合采用该方法。

ETag

ETag是对资源的特殊标识

Etag: W/"e563df87b65299122770e0a84ada084f"

请求该资源成功之后,将返回的ETag存入if-none-match字段中(浏览器自动记录了该字段信息),同样在请求资源时传递给服务器,服务器查询该编码对应的资源有无更新,无更新返回304状态,更新返回200并重新请求。

以下有个小例子,查询书籍更新:

当书籍信息查询之后,再次查询,服务器根据资源的ETag查询得知该资源没有进行更新,返回304状态码。

更新返回的数据信息,再次查询,返回200状态码,重新进行请求:

从返回的Request Headers可以看出,再次请求时,浏览器自动发送了If-Modified-SinceIf-None-Match两个字段,浏览器根据这两个字段中(If-None-Match 优先级大于 If-Modified-Since)来判断是否修改了资源。

ETag如何计算

ETag是针对某个文件的特殊标识,服务器默认采用SHA256算法生成。也可以采用其他方式,保证编码的唯一性即可。

缓存的优先级

根据上文优缺点的比对,可以得出以下的优先级顺序:

Cache-Control > Expires > ETag > Last-Modified

如果资源需要用到强制缓存,Cache-Control相对更加安全,协商缓存中利用ETag查询更新更加全面。

图片来源:浏览器缓存机制详解

缓存存储在哪 disk cache

disk cache为存储在硬盘中的缓存,存储在硬盘中的资源相对稳定,不会随着tab或浏览器的关闭而消失,可以用来存储大型的,需长久使用的资源。

当硬盘中的资源被加载时,内存中也存储了该资源,当下次改资源被调用时,会优先从memory cache中读取,加快资源的获取。

memory cache

memory cache即存储在内存中的缓存,内存中的内容会随着tab的关闭而释放。

当接口状态返回304时,资源默认存储在memory cache中,当页面关闭后,重新打开需要再次请求。

这两种存储方式的区别可以参考该回答

When you visit a URL in Chrome, the HTML and the other assets(like images) on the page are stored locally in a memory and a disk cache. Chrome will use the memory cache first because it is much faster, but it will also store the page in a disk cache in case you quit your browser or it crashes, because the disk cache is persistent.

当您访问chrome中的URL时,页面上的HTML和其他资产(如图像)将本地存储在内存和磁盘缓存中。Chrome将首先使用内存缓存,因为它的速度快得多,但它也会将页面存储在磁盘缓存中,以防您退出浏览器或它崩溃,因为磁盘缓存是持久的。

为什么有的资源一会from disk cache,一会from memory cache

三级缓存原理

先去内存看,如果有,直接加载

如果内存没有,择取硬盘获取,如果有直接加载

如果硬盘也没有,那么就进行网络请求

加载到的资源缓存到硬盘和内存,下次请求可以快速从内存中获取到

为什么有的请求状态码返回200,有的返回304 200 from memory cache

不访问服务器,直接读缓存,从内存中读取缓存。此时的数据时缓存到内存中的,当关闭进程后,也就是浏览器关闭以后,数据将不存在。

但是这种方式只能缓存派生资源。

200 from disk cache

不访问服务器,直接读缓存,从磁盘中读取缓存,当关闭进程时,数据还是存在。

这种方式也只能缓存派生资源

304 Not Modified

访问服务器,发现数据没有
更新,服务器返回此状态码。然后从缓存中读取数据。

薄荷应用

举一个简单的小

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101150.html

相关文章

  • 浏览器的缓存机制

    摘要:从浏览器角度来看,整个就是一个源服务器,从这个层面来说,浏览器和服务器之间的缓存机制,在这种架构下同样适用。如果命中,则返回,告诉浏览器资源未更新,可使用本地的缓存。 缓存类型 缓存在宏观上可以分成两类:私有缓存和共享缓存。共享缓存就是那些能被各级代理缓存的缓存。私有缓存就是用户专享的,各级代理不能缓存的缓存。 微观上可以分下面几类: 浏览器缓存 缓存存在的意义就是当用户点击back按...

    LeanCloud 评论0 收藏0
  • 深入理解 Webpack 打包分块(上)

    摘要:而一个哈希字符串就是根据文件内容产生的签名,每当文件内容发生更改时,哈希串也就发生了更改,文件名也就随之更改。很显然这不是我们需要的,如果文件内容发生了更改,的打包文件的哈希应该发生变化,但是不应该。前言 随着前端代码需要处理的业务越来越繁重,我们不得不面临的一个问题是前端的代码体积也变得越来越庞大。这造成无论是在调式还是在上线时都需要花长时间等待编译完成,并且用户也不得不花额外的时间和带宽...

    Rocko 评论0 收藏0
  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函数式编程前端掘金引言面向对象编程一直以来都是中的主导范式。函数式编程是一种强调减少对程序外部状态产生改变的方式。 JavaScript 函数式编程 - 前端 - 掘金引言 面向对象编程一直以来都是JavaScript中的主导范式。JavaScript作为一门多范式编程语言,然而,近几年,函数式编程越来越多得受到开发者的青睐。函数式编程是一种强调减少对程序外部状态产生改变的方式。因此,...

    cfanr 评论0 收藏0
  • 理解释 - 收藏集 - 掘金

    摘要:巧前端基础进阶全方位解读前端掘金我们在学习的过程中,由于对一些概念理解得不是很清楚,但是又想要通过一些方式把它记下来,于是就很容易草率的给这些概念定下一些方便自己记忆的有偏差的结论。 计算机程序的思维逻辑 (83) - 并发总结 - 掘金从65节到82节,我们用了18篇文章讨论并发,本节进行简要总结。 多线程开发有两个核心问题,一个是竞争,另一个是协作。竞争会出现线程安全问题,所以,本...

    AlphaGooo 评论0 收藏0
  • 理解释 - 收藏集 - 掘金

    摘要:巧前端基础进阶全方位解读前端掘金我们在学习的过程中,由于对一些概念理解得不是很清楚,但是又想要通过一些方式把它记下来,于是就很容易草率的给这些概念定下一些方便自己记忆的有偏差的结论。 计算机程序的思维逻辑 (83) - 并发总结 - 掘金从65节到82节,我们用了18篇文章讨论并发,本节进行简要总结。 多线程开发有两个核心问题,一个是竞争,另一个是协作。竞争会出现线程安全问题,所以,本...

    forrest23 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<