浏览器缓存
本文是对一文读懂前端缓存的总结。
可以分成 Service Worker、Memory Cache、Disk Cache 和 Push Cache,那请求的时候 from memory cache 和 from disk cache 的依据是什么,哪些数据什么时候存放在 Memory Cache 和 Disk Cache中?
浏览器端缓存的目的
分析一个完整的资源有3个步骤:
- 请求
- 处理
- 响应
对于浏览器,只能优化请求和响应。
缓存方式的分类
- memory cache
- disk cache
- service worker
memory cache
这个操作就很像我们平时写惰性函数一样做优化一样,浏览器同样需要做这样的优化,对于已请求过的资源保存一份引用到当前tab中,当Cache-Control: no-store时,不会去做保存引用的操作。
当tab未关闭,我们刷新网页时,会看到 from memory cache。
disk cache
就是存在本地的资源,它的存放策略严格按照 http 头字段,绝大部分的缓存都是指的 disk cache。
service worker
这个相当于浏览器开放的缓存API给开发者来使用。
浏览器访问资源处理逻辑
- 先走service worker ,如果没有命中,则走fetch
service worker 在 network 中显示的都是 from service worker,不能看出是否有真正的请求,需要从服务器上看access.log
才能知道。 - 再走 memory cache,命中则返回200
- 再走 disk cache,根据 Cache-Control 的设置:
- 缓存未失效,不请求,直接返回200
- 缓存已失效,使用协商缓存来对比资源是否发生变化,未变化则返回304,否则200.
- 发出请求(协商缓存也是要发请求的)
- 响应存入disk
- 根据是否no-store存入 memory
- 根据是否 cache.put 存入service worker
Disk cache - Http 头部字段
字段的定义分为2类
- 强制缓存
- Expires http/1.0
- Cache-Control http/1.1
- 协商缓存
- Last-Modified & If-Modified-Since http/1.0
- ETag & If-None-Match http/1.1
强制缓存,可以减少请求数。Cache-Control使用的相对时间,Expires使用的绝对时间。绝对时间与客户端有关系了,而相对时间没有。Cache-Control的常用值:
- max-age: 一年/一天
- must-revalidate 表示超过了 max-age 则必须重新发请求验证资源的有效性
- no-cache 交给协商缓存处理。本地还是会做缓存,请求还是会发出,但是决定权交给协商缓存的结果。
- no-store 不缓存
- public 客户端和代理服务器都可以缓存资源
- private 只有客户端才能缓存资源
这些配置一般在 nginx 做代理服务器时需要关注。
⚠️ max-age=0和no-cache等价么,理论上是的,严谨一点应该是 max-age=0, must-revalidate 和 no-cache 等价。
在http/1.0 no-cache只能用Pragma字段
协商缓存只能优化返回体的大小,Last-Modified & If-Modified-Since 是对比文件修改时间是否发生变化来决定是否需要返回响应体。Etag & If-None-Match 则是通过文件本身内容的特殊标识。
具体过程是:
- 服务器返回文件的修改时间,Last-Modified,浏览器存在本地
- 当需要使用协商缓存时,发出请求,将 Last-Modified 赋值给 If-Modified-Since
- 服务器将请求头中的 If-Modified-Since 和 资源的 Last-Modified 做对比
- 变化了则返回 304,反之200
⚠️ 所以 304 是协商对比的结果。其他情况都是200
应用场景
- no-cache 对于 ssr 博客文章经常变化的资源可以这么设置。
max-age=31536000, public
,不经常变化,比如 jquery 库的 CDN。
总结
强缓存本身就是一个很危险的操作,因为缓存在本地的资源很有可能被删除。原因:
- 本地缓存资源达到上限
- 相同文件的 max-age 不一致(被不同页面引用)
这样就会造成页面报错。