浏览器缓存

125 阅读5分钟

浏览器缓存

浏览器缓存在前端性能中是重要的一环。主要通过一下三个部分来学习浏览器缓存。

  1. 强缓存
  2. 协商缓存
  3. 缓存的位置

浏览器缓存有两种,一种是不需要发送http请求(强缓存),一种是需要发送http请求的(协商缓存)。

强缓存

http/1.0版本是用Expires,http/1.1版本Cache-Control

Expires

Expires: 即过期时间,存在服务端返回的相应头里,告诉浏览器在这个过期时间之前都是用缓存,不需要发送请求。

Expires: Wed, 22 Nov 2019 08:41:00 GMT

缺点:那就是服务器的时间和浏览器的时间可能并不一致,那服务器返回的这个过期时间可能就是不准确的。因此这种方式很快在后来的HTTP1.1版本中被抛弃了。

Cache-Control

本质上和Expires是一样的,就是控制过期时间。区别就是Cache-Control表示的是缓存过期时长而expires是过期时间点。

Cache-Control:max-age=3600

代表这个响应返回后在 3600 秒,也就是一个小时之内可以直接使用缓存。

Cache-Control的属性值

  • max-age:强缓存过期时长
  • public:浏览器和中间代理服务器都可缓存
  • private:浏览器缓存,中间代理服务器不可缓存
  • no-cache:不强缓存,走协商缓存
  • no-store:一律不缓存
  • s-maxage:和max-age很像,只不过是处理中间代理服务器的过期时长。

值得注意的是,当Expires和Cache-Control同时存在的时候,Cache-Control会优先考虑。

协商缓存

强缓存失效之后,浏览器在请求头中携带相应的缓存tag来向服务器发请求,由服务器根据这个tag,来决定是否使用缓存,这就是协商缓存。

缓存tag有两种:Last-Modify和Etag

Last-Modified

即最后修改时间。在浏览器第一次请求时,服务端返回相应头上带这个字段。

浏览器接收到后,在次请求会带上If-Modified-Since这个字段,这个字段的值就是服务端相应头Last-Modified的值。

  • 如果请求头中的这个值小于最后修改时间,说明是时候更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
  • 否则返回304,告诉浏览器直接用缓存。

ETag

ETag 是服务器根据当前文件的内容,给文件生成的唯一标识,只要里面的内容有改动,这个值就会变。服务器通过响应头把这个值给浏览器。

浏览器接收到这个相应后,再次请求,会在请求头带上If-None-Match字段,字段的值就是Etag的值。

  • 如果两者不一样,说明要更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
  • 否则返回304,告诉浏览器直接用缓存。

两者对比

  • 在精准度上,ETag优于Last-Modified。优于 ETag 是按照内容给资源上标识,因此能准确感知资源的变化。而 Last-Modified 就不一样了,它在一些特殊的情况并不能准确感知资源变化,主要有两种情况:
    • 编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。
    • Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了。
  • 在性能上,Last-Modified优于ETag,也很简单理解,Last-Modified仅仅只是记录一个时间点,而 Etag需要根据文件的具体内容生成哈希值。

如果两种方式都支持的话,服务器会优先考虑ETag。

缓存的位置

浏览器中的缓存位置一共有四种,按优先级从高到低排列分别是:

  • Service Worker
  • Memory Cache
  • Disk Cache
  • Push Cache

Service Worker

Service Worker 借鉴了 Web Worker的 思路,即让 JS 运行在主线程之外,由于它脱离了浏览器的窗体,因此无法直接访问DOM。虽然如此,但它仍然能帮助我们完成很多有用的功能,比如离线缓存消息推送网络代理等功能。其中的离线缓存就是 Service Worker Cache。

Memory Cache 和 Disk Cache

Memory Cache指的是内存缓存,从效率上讲它是最快的。但是从存活时间来讲又是最短的,当渲染进程结束后,内存缓存也就不存在了。

Disk Cache就是存储在磁盘中的缓存,从存取效率上讲是比内存缓存慢的,但是他的优势在于存储容量和存储时长。稍微有些计算机基础的应该很好理解,就不展开了。

那浏览器如何决定将资源放进内存还是硬盘呢?主要策略如下:

  • 比较大的JS、CSS文件会直接被丢进磁盘,反之丢进内存。
  • 内存使用率比较高的时候,文件优先进入磁盘。

Push Cache

即推送缓存,这是浏览器缓存的最后一道防线。它是 HTTP/2 中的内容,虽然现在应用的并不广泛,但随着 HTTP/2 的推广,它的应用越来越广泛。 push cache

总结

首先通过 Cache-Control 验证强缓存是否可用

  • 如果强缓存可用,直接使用
  • 否则进入协商缓存,即发送 HTTP 请求,服务器通过请求头中的If-Modified-Since或者If-None-Match字段检查资源是否更新
    • 若资源更新,返回资源和200状态码
    • 否则,返回304,告诉浏览器直接从缓存获取资源