通俗易懂,一文学会前端缓存

什么是web缓存

主要分为:浏览器缓存、http缓存

其中http缓存是web缓存的核心,最难懂也是最重要的一部分。

浏览器缓存,如localStorage,sessionStorage,cookie等等。这些功能主要用于缓存一些必要的数据,比如用户信息,需要携带给后端的参数。(一般只能保存5M左右的数据,多了不行)

所以接下来,我们的重点将围绕http缓存展开。

缓存可以解决什么问题?缺点是什么?

可以解决的问题:

  • 减少不必要的网络传输,节约宽带(省钱小窍门)
  • 更快的页面加载速度(加速)
  • 减少服务器负载,避免服务器过载(减载)

存在的缺点:

  • 占内存(有些缓存会被存储到内存中)

http缓存又分为两种:

  • 强制缓存
  • 协商缓存

强制缓存

简称强缓存。如果浏览器判断请求的目标资源有效命中强缓存,如果直接命中,则可以直接从内存中读取目标资源,无需于服务器做任何通讯。

基于Expires字段实现的强缓存

Expires的作用是,设定一个强缓存时间,在此时间范围内,则从内存或磁盘中读取缓存返回。

但是Expires已经被废弃了!对于强缓存来说,Expires已经不是实现强缓存的首选。

因为Expires判断强缓存是否过期的机制是:获取本地时间戳,并对比先前拿到资源文件的Expires字段做比较,这里就存在一个巨大的bug:如果我的本地时间不准怎么办?

对,Expires太过于依赖本地时间,如果本地时间与服务器时间不同步,就会出现资源无法被缓存或者资源永远被缓存的情况。所以,Expires字段几乎不被使用了。在现在的项目中,我们并不推荐使用Expires,强缓存功能通常使用cache-control字段代替Expires。

没想到吧,说了半天,结果是给废弃的东西。

基于Cache-control实现的强缓存

Cache-control完美解决了Expires本地时间的bug。

Cache-control的使用方法很简单,只要在资源的相应头上写上需要缓存多久就好了:

res.writeHead(200,{
    'Cache-Control':'max-age=10'
});

从资源第一次返回的时候开始,往后的10s中内如果资源在此请求,则从缓存中读取。

Cache-Control:max-age=NN就是需要缓存的秒数。从第一次请求资源的时候开始,往后N秒内,资源若再次请求,则直接从磁盘(或内存中读取),不与服务器做任何交互。

Cache-control中max-age后面的值上一个滑动时间,从服务器第一次返回该资源开始倒计时,所以不需要对比客户端与服务器之间的时间,也就解决了Expires的巨大bug。

Cache-control的属性:

  • max-age:客户端资源被缓存多久
  • s-maxage:代理服务器缓存的时长
  • no-cache:强制进行协商缓存(直接跳过强缓存的校验)
  • no-store:禁止任何资源缓存
  • public:资源可被浏览器缓存,也可被代理服务器缓存
  • private:资源只能被浏览器缓存

⚠️注意:public与private互斥,默认为private;max-age与s-maxage不互斥,可以一起使用

协商缓存

协商缓存的内容会有点绕,我们仔细看看。

基于last-modified的协商缓存

过程:

  1. 首先需要在服务器端读出文件修改时间
  2. 将读出来的修改时间赋值给响应头的last-modified字段
  3. 最后设置Cache-control:no-cache

这个过程缺一不可。

还没结束,到这里还不能实现协商缓存。

当客户端读取到last-modified的时候,会在下次请求标头中携带一个字段If-Modified-Since,而这个请求头中的If-Modified-Since就是服务器第一次修改时候给他的时间。那么之后每次对该资源的请求,都会带上If-Modified-Since这个字段,而服务端需要拿到这个时间并再次读取资源的修改时间,让两者做对比决定上读取缓存还是返回新的资源。

使用以上方法的协商缓存存在两个非常明显的bug,这两个bug都是基于文件是通过对比修改时间来判断是否内容更改的。

  1. 因为是根据文件修改时间来判断,所以,在文件内容本身不修改的情况下,依然有可能更新文件修改时间,导致缓存失效了。
  2. 当文件在极短时间内完成修改(几百毫秒),而文件修改时间的最小单位是秒,所以这个时候文件修改时间不会改变,导致依然不会返回新的文件

为了解决这两个bug,从http1.1开始新增了一个头信息,ETag,顶住!!马上就顺通了!

基于ETag的协商缓存

ETag就是将原先协商缓存的比较时间戳的形式 -> 比较文件指纹

文件指纹:根据文件内容计算出的唯一哈希值,一旦内容改变哈市值随之改变,指纹也改变。

过程:

  1. 第一次请求资源的时候,服务端读取文件并计算出文件指纹,将文件指纹放在响应头的ETag字段跟资源一起返给客户端
  2. 第二次请求资源时,客户端自动从缓存中读取上一次服务器返回的ETag。并赋给请求头的if-None-Match字段,让上一次的文件指纹跟随请求一起回到服务端
  3. 服务端拿到请求头的if-None-Match字段值,并再次读取目标资源生成文件指纹,两个指纹做对比,如果完全一致,则直接返回304状态码和一个空的相应体;如果不吻合,则说明文件被修改,那么将新的文件指纹放在响应头的ETag中返回给客户端

ETag也有缺点

  • ETag需要计算文件指纹,服务端需要更多的计算开销,如果文件尺寸大,数量多,计算频繁的话,ETag计算就会影响服务端性能,在这种场景下就不太适用
  • ETag又强验证和弱验证,所谓强验证,ETag生成的哈希码深入到每个字节。哪怕文件中只有一个字节改变了,也会生成不同的哈希值,所以强验证非常消耗计算量;弱验证是提取文件的部分属性来生成哈希值,因为不必精确到每个字节,所以整体速度较快,但准确率不高。

总结一下

  • http缓存可以减少带宽流量,加快响应速度
  • 关于强缓存,cache-control是Expires的完全替代方案,在可以使用cache-control的情况下不要使用expires
  • 关于协商缓存,etag并不是last-modified的完全替代方案,而是补充方案,具体用哪一个,取决于业务场景
  • 有些缓存是从磁盘读取,有些缓存是从内容中读取,有什么区别?从内存中读取的缓存更快
  • 所有带304的资源都是协商缓存,所有标注从内存/磁盘中读取的资源都是强缓存
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

椰卤工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值