前端缓存可以分为浏览器缓存 和 HTTP 缓存。(浏览器缓存就是浏览器本地存储的方式)
场景:
第一遍打开淘宝
刷新
从👆图中我们可以看到在size的位置有👇几个词的出现
- ServiceWorker
- memory Cache
- disk Cache
- 523k
他们的优先级是从上到下寻找, 找到就返回, 找不到则继续
那么这些词都是什么意思呢❓ 这就是缓存来自的位置!!下面一起来看看有关缓存的知识
一. 为什么需要缓存呢?
前端页面有些东西是重复的不变的,所以把他们放在缓存区里,如果命中直接去缓存区拿,性能上会得到大大的提升,是一种很好的web优化手段
二. 缓存都有几种?
首先来看个图, 然后看图详解
从上图中可以看出,按照位置划分的话,缓存一共分为3种,这里我们主要介绍第二种HTTP 缓存。
1.HTTP cache
disk缓存由HTTP请求字段控制: 通过请求头,响应头的字段指定缓存规则
HTTP缓存的好处:
- 减少冗余的数据传输,节省了网费
- 缓解了服务器的压力,大大提高了网站的性能
- 加快了客户端加载网页的速度
1.1强制缓存:减少请求数量
优先级高,如果这个生效,则不进行对比缓存。如果命中缓存就直接去缓存数据库取,不需要请求服务器减少请求数量,如果考虑优化网页性能,应首先被考虑
借用网上的一张图片
请求数据
if(命中缓存 && 没有过期){
缓存数据库 返回数据
}else{
1.没有命中缓存
2.向服务器请求数据.then(res=>{
3.拿到数据+ 缓存规则
})
4.将缓存规则 + 数据 存在缓存系统中
}
Expries (HTTP1.0+ 字段):是个绝对时间(GMT)
服务器返回的到期的有效时间。
缺点:因为缓存时间是服务端生成的,可能会和客户端有误差。
Cache-Control:(HTTP1.1字段):是个相对时间
现在浏览器默认使用都是HTTP1.1
Cache-Control是个相对时间值可以混用, 常用值有:
- private:私有缓存只能用于单独的用户(默认值),不能被代理服务器缓存
- public:共享缓存可以被多个用户使用
- no-cache:不适用强制缓存,走对比缓存
- max-age:缓存的过期时间
- no-store:一切都不缓存(Firfox需要cache-control:no-cache; no-store;)
- must-revalidata : 指定如果页面是过期的,则去服务器进行获取。这个指令并不常用,就不做过多的讨论了。
为了兼容可以Expries和Cache-Control都设置
注意:在HTTP1.0中,如果想使用no-cache,通常要使用pragma:no-cache(也是唯一值),但是这个字段只是浏览器约定俗成的实现,没有确切的规范,因为缺乏可靠性,在当前网络环境下其实用处已经很小了,pragma优先级高于cache-control,但是HTTP1.1 已经废弃了这个字段。
1.2对比缓存(协商缓存):响应体积节省
当强制缓存到期了,就需要使用对比缓存了
大概意思就是浏览器先请求缓存数据库,要一个标识,
拿着标识去找服务器确认,
服务器去对比last-modified||Etag字段判断是不是有更新,
没有更新就304,有的话就200,
然后再把新的规则+数据带给客户端,
客户端在把数据和规则写进缓存服务器
【304只是个状态码,并没有实际的文件内容,因为体积节省了,从而得到了优化】
1. 向缓存服务器发请求
2. 缓存数据返回标识(比如Etag='2020')
3. 浏览器把Etag的值赋值在请求头IF-None-Match中,然后传给服务端 此时IF-None-Match='2020'
if(IF-None-Match == Etag){ //未修改
获取缓存数据显示304
}else{
返回数据 + 缓存规则(比如Etag='2030') 返回200
客户端将数据 + 缓存规则(Etag='2030')存入 缓存系统
}
Last-Modified & If-Modified-Since:
服务器通过 Last-Modified 字段告知客户端,资源最后一次被修改的时间
缺点:
- 最后一次的时间可能获取的不准确
- 如果资源更新的速度是秒以下单位,那么该缓存是不能被使用的,因为它的时间单位最低是秒。
- 如果文件是通过服务器动态生成的,那么该方法的更新时间永远是生成的时间,尽管文件可能没有变化,所以起不到缓存的作用。
Etag & If-None-Match
为了解决上述问题,出现了一组新的字段 Etag 和 If-None-Match.
- Etag 存储的是文件的特殊标识(一般都是 hash 生成的)
- 之后的流程和 Last-Modified 一致,只是字段不同
- 服务器同样进行比较,命中返回 304, 不命中返回新资源和 200。
- Etag 的优先级高于 Last-Modified
2.memory Cache:
黑盒:是浏览器为了加快读取速度而进行的自身的优化行为,不受开发者,也不受请求头的控制
- 几乎所有的网络请求都会被自动加入到Memory Cache中
- 正常情况下关闭tab就会清除,极端情况内存占得太多,前面的也会清除
- 一个页面有2个相同的请求,只请求一次,避免浪费
- 在从MC读缓存的时候,浏览器会忽略max-age和nocache等头设置,因为它是短期的存储
- no-store 可以使一切都不缓存
3.ServiceWorker:
由开发者控制:SW缓存较对其他缓存更灵活,他可以选择缓存哪些文件,什么情况下缓存,取出哪些缓存
我们可以从F12 Application->Cache Storage 找到它。
这个缓存是永久的,及时关闭了tab或者浏览器,下次打开依然在。
如果没有命中缓存,会fetch()方法继续获取资源。
这时候浏览器会去memory和disk中进行下一次找缓存的工作了
如果要清除,手动调用Api cache delete。或者超容量了被浏览器清除了
经过ServiceWorker的fetch()获取的资源,即便他没有命中SW缓存,甚至走了网络请求,也会被标记成from SW
三、看完知识点来看下面的具体例子吧
eg0:内存缓存
eg1:强制缓存
eg2:对比缓存
四、总结:
缓存大致分为三种
- memory cache: 不受开发者控制,是浏览器自发的行为,关闭tab就清除了
- disk磁盘缓存也就是HTTP缓存,顾名思义受HTTP头的控制。分为2种:
- 强缓存(级别更高):减少请求数量
- 有缓存的话:不需要与服务器交互,直接从缓存数据库里拿
- 失效情况:
expires,max-age 过期了,则走对比缓存cache-control 设置为 no-cache, 则走对比缓存
- 对比缓存(协商缓存):无论怎么都与服务端交互,但是304时体积会减小
- last-modified / if-modified-since (http1.0)
- Etag / If-None-Match (HTTP1.1):级别更高
- 强缓存(级别更高):减少请求数量
- servciceWorker是开发者开发的脚本,可控制,更灵活
浏览器的强制刷新其实就是发动的请求头都带有no-cache.
强制缓存,命中缓存的时候会直接从缓存数据库拿数据,所以会减少请求数量,返回的状态码是200。当expires 或者cache-control 的max-age 失效,或者设置了no-cache 时,会走对比缓存
而对比缓存一定会与服务器交互,第一次请求后,服务端会返回一个最后修改时间,第二次请求时,浏览器会在请求头里带上这个字段,让服务端去对比,如果资源发生改变,则返回数据和新的缓存规则,状态码200。如果发现没有修改,则返回状态码304但是不返回数据内容,直接使用缓存数据库里的数据。所以他会节省响应体积,对比缓存的2对字段可以都写上,但是Etag的级别更高。
对比缓存2字段的区别就是Etag是HTTP1.1,另外他可以解决Last-modified 存在的一些不准确的问题