01 前言
作为一个合格的前端工程师,浏览器相关的工作原理是我们进行性能优化的基石,了解浏览器原理也是前端系统知识体系中的重要一环。
那关于浏览器的缓存你知道多少呢,本文将详细的来聊一聊浏览器的缓存问题
02 浏览器的缓存
缓存是性能优化中非常重要的一环,浏览器的缓存机制对开发也是非常重要的知识点。浏览器的缓存分为强缓存和协商缓存两种。
强缓存
检查阶段无需发送HTTP请求,直接通过服务器返回的响应头中相应的字段来检查是否有效的缓存称为强缓存。
检查字段存在于服务器返回的响应头中,告诉浏览器在过期时间前可以直接从缓存中获取数据,无需再次请求,在早期HTTP/1.0
时代,该字段为Expires,而HTTP/1.1
以后使用的是Cache-Control。
Expires
Expires: Tue, 16 Jun 2020 15:08:00 GMT
表示资源有效期到2020年6月16号15点08分
,过了有效期就需要重新想服务器请求资源。
由于服务器的时间和浏览器的时间可能并不一致,因此这种方式返回的过期时间可能并不准确,在HTTP1.1版本中就抛弃了。
Cache-Control
Cache-Control:max-age=3600
表示资源在3600s之内都可以直接使用。它和Expires本质的不同在于它并没有采用具体的过期时间这个方式,而是采用过期时长来控制缓存。
Cache-Control可以与多个指令结合
- public: 客户端和代理服务器都可以缓存。
- private: 只有浏览器能缓存了,中间的代理服务器不能缓存。
- no-cache: 跳过当前的强缓存,发送HTTP请求,即直接进入协商缓存阶段。
- no-store: 非常粗暴,不进行任何形式的缓存。
- s-maxage: 这和max-age长得比较像,但是区别在于s-maxage是针对代理服务器的缓存时间。
值得注意当Expires与Cache-Control同时存在时,优先考虑Cache-Control。
协商缓存
强缓存失效之后,浏览器在请求头中携带相应的缓存tag来向服务器发请求,由服务器根据这个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,告诉浏览器直接用缓存。
两者对比
在精准度上,ETag 优于 Last-Modified。ETag 是按照内容给资源上标识,因此能准确感知资源的变化。而 Last-Modified 是针对最后的修改时间,在一些特殊的情况并不能准确感知资源变化,主要有两种情况:
- 编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。
- Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了。
在性能上,Last-Modified 优于 ETag。如果两种方式都支持的话,服务器会优先考虑 ETag
缓存位置
前面我们已经提到,当强缓存有效或者协商缓存中服务器返回304时,我们直接从缓存中获取资源。那这些资源究竟缓存在什么位置呢?
浏览器中的缓存位置一共有四种,按优先级从高到低排列分别是:
- Service Worker Cache - 借鉴了 Web Worker的 思路,即让 JS 运行在主线程之外
- Memory Cache - 内存缓存,效率最快,存活时间最短,渲染进程结束后,内存缓存也就不存在了
- Disk Cache - 磁盘缓存,效率比内存缓存慢,存储容量大和存储时间长,存放大的JS、CSS文件,以及内存使用率高时的文件
- Push Cache - 即推送缓存,这是浏览器缓存的最后一道防线。它是 HTTP/2 中的内容
03 总结
浏览器的缓存机制:
- 首先通过 Cache-Control 验证强缓存是否可用,如果强缓存可用,直接使用
- 进入协商缓存,即发送 HTTP 请求,服务器通过请求头中的
If-Modified-Since
或者If-None-Match
字段检查资源是否更新 - 若资源更新,返回资源和200状态码,否则返回304,告诉浏览器直接从缓存获取资源