Skip to content
On this page

浏览器缓存机制

缓存可以说是性能优化中简单高效的一种优化方式了,它可以显著减少网络传输所带来的损耗。

对于一个数据请求,可以分为三个步骤:

  • 网络请求

  • 后端处理

  • 浏览器响应

浏览器缓存可以帮助我们在第一和第三个步骤中优化性能。比如说直接使用缓存而不发起请求,或者发起了请求但后端存储的数据和前端一致,那么就没有必要再将数据回传回来,这样就减少了响应数据。

浏览器缓存机制:

  • 缓存位置

  • 缓存策略

  • 实际场景应用缓存策略

缓存位置

从缓存位置上来说分为四种,并且各有优先级,当依次查找缓存且都没有命中的时候,才会请求网络

  • Service Worker

  • Memory Cache

  • Disk CaChe

  • Push Cache

  • 网络请求

Memory Cache

Memory Cache 是内存缓存,读取内存的中的数据肯定比磁盘快。但是内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。一但我们关闭 Tab 页面,内存中的缓存也就被释放了。

当我们访问过页面,再次刷新页面

hc.png

既然缓存这么高效,是不是可以让数据都存放在内存中呢?

当然这是不可能的。计算机内存比硬盘容量小的多,系统不可能都把文件存在内存中。存储大部分:JS、CSS、HTML、图片等,但是浏览器会把哪些文件存在内存这个过程很玄学

  • 对于大文件,大概率不会存在内存,反之

  • 当前系统内存使用率高,文件优先存储硬盘

Disk Cache

Disk Cache 是硬盘缓存,读取速度稍慢,但是什么都能存储。比 Memory Cache 胜在容量和存储时效性

Disk Cache 会根据 HTTP Hearder 中请求头字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。并且即使在跨站点的情况下,相同地址的资源一旦被硬盘缓存下来,就不会再次去请求数据了。

缓存策略

分为两种:

  • 强缓存

  • 协商缓存

通过设置 HTTP Header 实现。

强缓存

强缓存表示在缓存期间不需要请求,通过设置请求头参数:

  • Expires
bash
Expires: Fri, 13 May 2022 09:32:00 GMT

Expires 表示资源会在 Fri, 13 May 2022 09:32:00 GMT 后过期,需要再次请求。且它受限于本地时间,如果本地时间修改,可能会造成缓存失效。

  • Cache-Control
bash
Cache-control: max-age=30

Cache-Control 优先级高于 Expires 。表示资源会在 30s 过期,需要再次请求。

常见指令

指令作用
public表示响应可以被客户端和代理服务器缓存
private响应只可以被客户端缓存
max-age=30缓存 30s 后就过期,需要重新请求
s-maxage=30覆盖 max-age,作用一样,只在代理服务器中生效
no-store不缓存任何响应
no-cache资源被缓存,但是会立即失效,下次会发起请求验证资源是否过期
max-stale=3030s 内,即使缓存过期,也使用该缓存
min-fresh=30希望在 30s 内获取最新的响应

协商缓存

如果缓存过期,就需要发起请求验证资源是否有更新。

设置请求头:

  • Last-Modified

  • ETag

当浏览器发起请求验证资源时,如果资源没有改变,那么服务端返回 304 状态码,并且更新浏览器缓存有效期。

  • Last-Modified

它表示本地文件最后修改日期,If-Modified-Since 会将 Last-Modufued 的值发送给服务器,询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来,否则返回 304 状态码。

弊端:

  • 如果本地打开缓存文件,即使没有对文件进行修改,但还是会造成 Last-Modified 被修改,服务端不能命中缓存导致发送相同的资源

  • 因为 Last-Modified 只能以秒计时,如果不可感知的时间内修改完成文件,那么服务端会认为资源还是命中了,不会返回正确的资源

因此,在 HTTP / 1.1 出现了 ETag

  • ETag

ETag 类似文件指纹,If-None-Match 会将当前 ETag 发送给服务器,询问该资源 ETag 是否变动,存在变化就将新的资源发送回来。

ETag 优先级比 Last-Modified 高。

如果什么缓存策略都没设置,那么浏览器会怎么处理?

对于这种情况,浏览器会采用一个启发式的算法,如果请求头存在 Last-Modified 通常会取响应头中的 Date 减去 Last-Modified 值的 10% 做为缓存时间。

实际场景

对于频繁变动的资源,首先需要使用 Cache-Control: no-cache 使浏览器每次都请求服务器,然后配合 ETag 或者 Last-Modified 来验证资源是否有效。这样的做法虽然不能节省请求数量,但是能显著减少响应数据大小

为什么减少响应数据大小:文件没有改变,返回304,使用了缓存文件

HTML 文件一般不缓存或者缓存时间很短

其他文件进行哈希处理:

现在都会使用工具来打包代码,只有当代码修改后才会生成新的文件名。基于此,我们就可以给代码文件设置缓存有效期一年 Cache-Control: max-age=31536000,这样只有当 HTML 文件中引入的文件名发生了改变才会去下载最新的代码文件,否则就一直使用缓存。

浏览器缓存机制

expires.png