浏览器缓存机制

2,179 阅读6分钟

如果面试一个要求一定的工作经验的前端岗位的话,前端缓存是一个绕不过去的面试题。然而大部分前端在工作中接触较少或者没有去专门学习过,可能就导致回答不上问题或者都是在面试之前临时抱佛脚,面试完成后大脑又如白纸。

工作这么多年,虽然也常常遇到此类问题,但大多时候都是临时查找相关文章学习。因为没有深入的学习研究,所以这方面一直都是自己的知识盲区。最近终于花了一些时间学习相关的知识,在此记录下学习收获,以便加深记忆和认知,及日后复习。

什么是浏览器缓存?

浏览器缓存是为了节约网络的资源加速浏览,浏览器在用户磁盘上对最近请求过的文档进行存储,当访问者再次请求这个页面时,浏览器就可以从本地磁盘显示文档,这样就可以加速页面的阅览。浏览器缓存主要包括强缓存和协商缓存。 -- 百度百科

浏览器缓存也称为http缓存。

通俗地说,浏览器缓存指的是浏览器为了节省网络资源及加快页面渲染,将请求过的资源缓存在本地(硬盘和内存中),再根据http响应头来判断是否读取本地的缓存资源。

强缓存(200 from disk cache 或者 200 from memory cache, 硬盘缓存和内存缓存)

强缓存指的是浏览器缓存了该请求的资源且根据缓存标识(响应头的cache-control:max-age 及 expires)判定资源未过期。

协商缓存(304)

协商缓存指的是浏览器缓存了该请求的资源但未能判断资源是否过期,需要向服务器发起携带缓存标识(响应头的 last-modified 及 Etag)的请求来询问资源是否过期。

浏览器缓存相关响应头

强缓存相关

Expires

Expires 是 HTTP/1.0 中控制浏览器缓存的字段,其值为服务器返回的该请求结果缓存的到期时间。当浏览器再次发起请求时,如果客户端时间早于到期时间,则直接读取缓存结果而不用再次发起请求。

因为这边用到了客户端的时间进行判断,所以可能会因为客户端时间和服务器时间不同导致预期之外的缓存行为

Cache-Control

cache-control 是HTTP/1.1 的字段,是控制缓存的重要规则,它的值包含了几组可选的值,中间使用逗号相隔开

  1. 控制代理服务器缓存
  • public:所有内容被缓存(代理服务器和客户端都可缓存)

  • private(默认):仅客户端可缓存

  1. 控制是否缓存
  • no-cache:客户端缓存内容,是否使用缓存需要与服务器进行协商

  • no-store:所有内容不会被缓存

  1. 控制缓存有效期
  • max-age:其值为资源的有效时间(秒),表示缓存将在xx秒后失效

当 max-age 和 expires 同时存在时,只有 max-age 有效,expires 将不再生效

协商缓存相关

last-modified

last-modified 用于标识资源的最新修改时间,用于标记内容是否更新。

响应头的 last-modified 会作为缓存标识一起存储与缓存中,当再次请求需要进行服务器协商时,请求头的 if-Modified-Since 字段将带上缓存中的 last-modified 的值与服务器的资源修改时间进行比较,判断缓存是否过期。

使用 last-modified 有可能出现服务器资源未产生实质性更新但是修改时间更新的情况,比如资源重写。

Etag

Etag 是服务器根据资源内容通过一系列算法计算得出的用于标识资源的字符串编码,当资源内容有修改时,对应的 Etag 也会更新。其主要功能就是用于标记资源内容是否更新。

同样的,响应头的 Etag 会作为缓存标识一起存储于缓存中,当再次请求需要进行服务器协商时,请求头的 if-None-Match 字段将带上缓存中的 etag 值与服务器上资源的 Etag 进行比较,判断缓存是否过期。

当 Etag 和 last-modified 同时出现时,以 Etag 的标识为准。

浏览器缓存相关的请求头

Cache-Control

  • no-cache:强制向源服务器再次验证,控制代理服务器不能直接返回缓存

  • max-age:响应的最大age值,可以设置max-age=0使用协商缓存

if-modified-since

配合 last-modified 使用

if-None-Match

配置 Etag 使用

完整的浏览器缓存过程

  1. 判断本地是否有缓存,如果本地没有缓存资源则进入第4步,如果有则进入第2步。

  2. 通过 expires 和 max-age 判断缓存是否过期,如果未过期则直接返回资源(200 from cache)。否则进入第3步。

  3. 携带缓存标识(if-modified-since if-None-Match)进行请求,与服务器协商验证缓存是否过期,如果未过期则服务器返回不带资源实体的响应,浏览器从缓存中获取资源并返回给前端(304),否则进入第4步。

  4. 正常请求资源,服务器返回资源(200)并进行缓存。

缓存相关知识点

缓存的位置

浏览器缓存的存储位置分为硬盘(disk cache)和内存(memory cache),浏览器的读取顺序为内存->硬盘。

不同的资源可能会缓存在不同的位置

  1. css:因为 css 解析构建 CSSOM 树之后就不需要使用了,所以会被缓存在硬盘中,读取时从硬盘读取。

  2. JS 和图片:因为浏览器解析JS和图片之后,会将其放在内存中,所以优先读取内存(实践证明并非一定),当打开新窗口或者浏览器时则读取硬盘缓存。

不同的用户行为导致的缓存问题

刷新(F5/Command+r)

刷新时会给文档请求头加上 Cache-Control:max-age=0,所以文档一般会触发协商缓存。而文档之外的其他资源(JS css)则正常请求(可能会触发强缓存或协商缓存)。

强制刷新(CTRL + F5/Command+shift+r/勾选disable cache)

强制刷新时会给请求头加上 Cache-control: no-cache,使用协商缓存,但同时会删除协商缓存字段(if-modified-since if-none-match),所以最终结果都是从服务器请求新资源。

以上仅针对文档请求,而对于文档内的JS等资源,需要勾选disable cache才会添加cache-control:no-cache.

关闭浏览器/打开新标签

没有特殊操作,有可能使用强缓存或协商缓存。

参考


欢迎到前端学习打卡群一起学习~516913974