Skip to content
On this page

浏览器缓存

本文是对一文读懂前端缓存的总结。

可以分成 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给开发者来使用。

浏览器访问资源处理逻辑

  1. 先走service worker ,如果没有命中,则走fetch
    service worker 在 network 中显示的都是 from service worker,不能看出是否有真正的请求,需要从服务器上看 access.log 才能知道。
  2. 再走 memory cache,命中则返回200
  3. 再走 disk cache,根据 Cache-Control 的设置:
    1. 缓存未失效,不请求,直接返回200
    2. 缓存已失效,使用协商缓存来对比资源是否发生变化,未变化则返回304,否则200.
  4. 发出请求(协商缓存也是要发请求的)
  5. 响应存入disk
  6. 根据是否no-store存入 memory
  7. 根据是否 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 不一致(被不同页面引用)

这样就会造成页面报错。