前言
缓存是性能优化中非常重要的一环,浏览器的缓存机制对开发是非常重要的知识点:
- 强缓存
- 协商缓存
- 缓存位置
强缓存
当浏览器发起请求时,首先会先检查强缓存,如果命中则不进行请求,资源直接从磁盘或者缓存中读取
那浏览器如何检查是否命中强缓存呢?
在http/1.0中使用的是Expires字段,而http/1.1中使用的是Cache-Control字段
Expires
Expires指的是过期时间,存在请服务器返回响应头中,它的作用就是告诉浏览器在这个过期时间之前不需要再次发起请求,资源可以在缓存中获取。 例如:
Expires: Wed, 22 Nov 2021 08:41:00 GMT
表示资源在2021年11月22号8点41分过期,过期了就得向服务端发请求。
但是这种检查方式有个坑点,就是服务端(服务器)和客户端(浏览器)的时间可能会不一致,导致服务端返回的时间会不准确,所以HTTP/1.1使用Cache-Control来检查强缓存
Cache-Control
在Http1.1中,采用的是Cache-Control,也是存在请服务器返回响应头中
它和Expires本质的不同就是没有采用具体的时间点,而是采用过期时长来控制缓存,对应的字段是max-age 例如:
Cache-Control:max-age=3600
代表这个响应返回后的一小时之内可以使用缓存,超过一小时需要发起请求
Cache-Control不知有max-age一个属性,还有代表其他功能的属性如:
- private:表示只有浏览器能对资源进行缓存,中间的代理服务器不能缓存
- no-cache:表示跳过当前强缓存,直接发起Http请求,直接进入协商缓存
Google Chrome浏览器调式工具中的Disable cache就是使用这个字段的特性强制浏览器发起请求
- no-store: 表示不进行任何形式的缓存。
- s-maxage:表示针对代理服务器的缓存时间。
- must-revalidate: 表示缓存过期的时候,加上这个字段一旦缓存过期,就必须回到源服务器验证
注意:当两者同时存在时,优先Cache-Control
协商缓存
当强缓存失效,浏览器就会再次发送请求来向服务器获取资源
当浏览器再次发起请求的时候会带上一个标识【缓存tag】发起请求,服务器会根据这个请求判断是否决定使用协商缓存
缓存tag分为两种,Last-Modified 和 ETag
Last-Modified
即最后修改时间,在浏览器第一次向服务器发送请求时,服务器会在响应头中加上这个字段。
浏览器接收后,如果强缓存失效,再次发起请求时就会在请求头带上If-Modified-Since,这个字段的值也就是服务器传来的最后修改时间。
服务器拿到请求头中的If-Modified-Since的字段后,其实会和这个服务器中该资源的最后修改时间对比:
- 如果请求头中的这个值小于服务器中的最后修改时间,说明是时候更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
- 否则返回304,告诉浏览器直接用缓存。
ETag
ETag是服务器给当前文件的内容生产的一个唯一标识,只要这个文件的内容发生了变动,这个值就会随之发生改变,服务器通过响应头把这个值给浏览器
浏览器接收到ETag的值,会在下次请求时,将这个值作为If-None-Match这个字段的内容,并放到请求头中,然后发给服务器。
服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行比对:
如果两者不一样,说明要更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。 否则返回304,告诉浏览器直接用缓存。
两者对比 1、ETag比Last-Modified更精准,ETag直接精准到文件资源的内容有无发生改变从而判断有无更新,而Last-Modified则是通过时长 2、Last-Modified在性能上比ETag更有优势,因为Last-Modified只是生成一个时间点,而ETag则是根据文件的具体内容生成哈希值
缓存位置
从上面可以知道强缓存和协商缓存阶段,浏览器都是从缓存中获取资源的,那问题来了,这些缓存存放在电脑的哪个位置呢?
浏览器的缓存可以有四个位置存放,优先级从高到低:
- Service Worker
- Memory Cache
- Disk Cache
- Push Cache
Service Worker
Service workers 本质上充当 Web 应用程序、浏览器与网络(可用时)之间的代理服务器。这个 API 旨在创建有效的离线体验,它会拦截网络请求并根据网络是否可用来采取适当的动作、更新来自服务器的的资源。它还提供入口以推送通知和访问后台同步 API。即让 JS 运行在主线程之外,由于它脱离了浏览器的窗体,因此无法直接访问DOM。虽然如此,但它仍然能帮助我们完成很多有用的功能,比如离线缓存、消息推送和网络代理等功能,其中的离线缓存就是 Service Worker Cache。
Memory Cache 和 Disk Cache
Memory Cache指的是内存缓存,从效率上讲它是最快的。但是从存活时间来讲又是最短的,当渲染进程结束后,内存缓存也就不存在了。
Disk Cache就是存储在磁盘中的缓存,从存取效率上讲是比内存缓存慢的,但是他的优势在于存储容量和存储时长。稍微有些计算机基础的应该很好理解,就不展开了。
好,现在问题来了,既然两者各有优劣,那浏览器如何决定将资源放进内存还是硬盘呢?主要策略如下:
比较大的JS、CSS文件会直接被丢进磁盘,反之丢进内存 内存使用率比较高的时候,文件优先进入磁盘