浏览器缓存机制
缓存可以说是性能优化中简单高效的一种优化方式了,它可以显著减少网络传输所带来的损耗。
对于一个数据请求,可以分为三个步骤:
网络请求
后端处理
浏览器响应
浏览器缓存可以帮助我们在第一和第三个步骤中优化性能。比如说直接使用缓存而不发起请求,或者发起了请求但后端存储的数据和前端一致,那么就没有必要再将数据回传回来,这样就减少了响应数据。
浏览器缓存机制:
缓存位置
缓存策略
实际场景应用缓存策略
缓存位置
从缓存位置上来说分为四种,并且各有优先级,当依次查找缓存且都没有命中的时候,才会请求网络
Service Worker
Memory Cache
Disk CaChe
Push Cache
网络请求
Memory Cache
Memory Cache
是内存缓存,读取内存的中的数据肯定比磁盘快。但是内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。一但我们关闭 Tab 页面,内存中的缓存也就被释放了。
当我们访问过页面,再次刷新页面
既然缓存这么高效,是不是可以让数据都存放在内存中呢?
当然这是不可能的。计算机内存比硬盘容量小的多,系统不可能都把文件存在内存中。存储大部分:JS、CSS、HTML、图片等,但是浏览器会把哪些文件存在内存这个过程很玄学
对于大文件,大概率不会存在内存,反之
当前系统内存使用率高,文件优先存储硬盘
Disk Cache
Disk Cache
是硬盘缓存,读取速度稍慢,但是什么都能存储。比 Memory Cache
胜在容量和存储时效性。
Disk Cache
会根据 HTTP Hearder
中请求头字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。并且即使在跨站点的情况下,相同地址的资源一旦被硬盘缓存下来,就不会再次去请求数据了。
缓存策略
分为两种:
强缓存
协商缓存
通过设置 HTTP Header
实现。
强缓存
强缓存表示在缓存期间不需要请求,通过设置请求头参数:
Expires
Expires: Fri, 13 May 2022 09:32:00 GMT
Expires
表示资源会在 Fri, 13 May 2022 09:32:00 GMT
后过期,需要再次请求。且它受限于本地时间,如果本地时间修改,可能会造成缓存失效。
Cache-Control
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=30 | 30s 内,即使缓存过期,也使用该缓存 |
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
文件中引入的文件名发生了改变才会去下载最新的代码文件,否则就一直使用缓存。