Open ChuChencheng opened 4 years ago
深入理解浏览器的缓存机制
跟着这篇文章整理的
install
fetch
内存中的缓存。
<link rel="prefetch">
硬盘中的缓存。
关于哪些文件会缓存在内存、哪些在硬盘中:
浏览器根据请求资源时返回的响应头来判断资源是否该缓存; 根据请求头与响应头判断如何使用缓存。
不会发起请求,直接从缓存中读取资源,在 Devtool 中可以看到资源请求返回 200 状态码, Size 显示 from disk cache 或 from memory cache
通过设置 Expires 和 Cache-Control 两个 header 实现
Expires
Cache-Control
指令:
Expires 与 Cache-Control 区别在于,前者是 HTTP/1.0 的产物,二者同时存在时, Cache-Control 优先级更高。在不支持 HTTP/1.1 的环境下则 Expires 有效。现阶段 Expires 只是一种兼容的写法。
强缓存是基于时间来判断是否使用缓存,而不关心服务端文件是否已经更新,这可能导致拿不到最新的文件。
在强缓存失效后,就会使用协商缓存; 协商缓存会发起请求,由服务器根据缓存标识决定是否使用缓存; 如果协商缓存有效,则响应 304 状态码, Not Modified 并且不会发送资源,否则会返回 200 状态码与请求资源结果。
协商缓存可以通过两对 headers 实现:
Last-Modified 记录文件在服务器上的最后修改时间,当浏览器请求这个文件时,会带上 Last-Modified 请求头。
当浏览器下次请求这个资源时,如果有 Last-Modified 请求头,则会添加 If-Modified-Since ,值为 Last-Modified 的值。
当服务器收到请求时,会将浏览器发送的 If-Modified-Since 值与请求资源的最后修改时间进行对比,如果没有变化,则返回 304 使用缓存;如果小于服务器中这个资源的最后修改时间,则表示文件有更新,返回新的资源和 200 。
缺陷:
ETag 是服务端返回的当前资源的唯一标识(服务端生成),只要资源有变化,则 ETag 会重新生成。
浏览器下次请求缓存文件时,会把上一次的 ETag 放入 If-None-Match 中,服务端接收到请求后,会对比 If-None-Match 与服务器上文件的 ETag ,来判断该资源是否有更新。
ETag 的优势在于精确度高于以秒为精度的 Last-Modified
其缺点则是服务端要计算 hash 要耗费性能
在优先级上,服务器优先考虑 ETag
没有一个绝对通用的缓存策略,只有根据不同的场景来使用不同的策略才能发挥缓存的作用。
对于频繁变动的资源,使用 Cache-Control: no-cache ,这样,浏览器每次请求此类资源都会发起请求,配合 ETag 或 Last-Modified 来验证缓存资源是否有效。
Cache-Control: no-cache
此做法不能节省请求,但可以减少响应数据的大小。
对于这类资源通常使用 Cache-Control: max-age=31536000 ,配置一个较大的 max-age ,这样浏览器会使用强缓存,而不会发起请求。
Cache-Control: max-age=31536000
如果遇到文件更新,则通过改变文件名的方式更新,旧的资源则因 URL 不同,不会再被请求而弃用。
这个场景在平时用得比较多,例如线上引用的 JS、CSS 等资源,在文件名后面都会加上一个 hash 值。
这部分与浏览器或许不是很相关
衡量缓存是否有效的重要指标
命中率=返回正确结果数/请求缓存次数
能存放缓存的最大个数,超过这个数量,则会触发清空策略
合理设置最大元素值可提高缓存的命中率
一些简单的策略:
思维导图
深入理解浏览器的缓存机制
跟着这篇文章整理的
缓存位置
1. Service Worker
install
事件中缓存文件fetch
事件中拦截网络请求,判断是否命中缓存fetch
函数2. Memory Cache
内存中的缓存。
<link rel="prefetch">
3. Disk Cache
硬盘中的缓存。
关于哪些文件会缓存在内存、哪些在硬盘中:
4. Push Cache
缓存类型
浏览器根据请求资源时返回的响应头来判断资源是否该缓存; 根据请求头与响应头判断如何使用缓存。
1. 强缓存
不会发起请求,直接从缓存中读取资源,在 Devtool 中可以看到资源请求返回 200 状态码, Size 显示 from disk cache 或 from memory cache
通过设置
Expires
和Cache-Control
两个 header 实现Expires
Cache-Control
指令:
两者对比
Expires 与 Cache-Control 区别在于,前者是 HTTP/1.0 的产物,二者同时存在时, Cache-Control 优先级更高。在不支持 HTTP/1.1 的环境下则 Expires 有效。现阶段 Expires 只是一种兼容的写法。
强缓存是基于时间来判断是否使用缓存,而不关心服务端文件是否已经更新,这可能导致拿不到最新的文件。
2. 协商缓存
在强缓存失效后,就会使用协商缓存; 协商缓存会发起请求,由服务器根据缓存标识决定是否使用缓存; 如果协商缓存有效,则响应 304 状态码, Not Modified 并且不会发送资源,否则会返回 200 状态码与请求资源结果。
协商缓存可以通过两对 headers 实现:
Last-Modified 和 If-Modified-Since
Last-Modified 记录文件在服务器上的最后修改时间,当浏览器请求这个文件时,会带上 Last-Modified 请求头。
当浏览器下次请求这个资源时,如果有 Last-Modified 请求头,则会添加 If-Modified-Since ,值为 Last-Modified 的值。
当服务器收到请求时,会将浏览器发送的 If-Modified-Since 值与请求资源的最后修改时间进行对比,如果没有变化,则返回 304 使用缓存;如果小于服务器中这个资源的最后修改时间,则表示文件有更新,返回新的资源和 200 。
缺陷:
ETag 和 If-None-Match
ETag 是服务端返回的当前资源的唯一标识(服务端生成),只要资源有变化,则 ETag 会重新生成。
浏览器下次请求缓存文件时,会把上一次的 ETag 放入 If-None-Match 中,服务端接收到请求后,会对比 If-None-Match 与服务器上文件的 ETag ,来判断该资源是否有更新。
ETag 的优势在于精确度高于以秒为精度的 Last-Modified
其缺点则是服务端要计算 hash 要耗费性能
在优先级上,服务器优先考虑 ETag
应用场景
没有一个绝对通用的缓存策略,只有根据不同的场景来使用不同的策略才能发挥缓存的作用。
1. 频繁变动的资源
对于频繁变动的资源,使用
Cache-Control: no-cache
,这样,浏览器每次请求此类资源都会发起请求,配合 ETag 或 Last-Modified 来验证缓存资源是否有效。此做法不能节省请求,但可以减少响应数据的大小。
2. 不常变化的资源
对于这类资源通常使用
Cache-Control: max-age=31536000
,配置一个较大的 max-age ,这样浏览器会使用强缓存,而不会发起请求。如果遇到文件更新,则通过改变文件名的方式更新,旧的资源则因 URL 不同,不会再被请求而弃用。
这个场景在平时用得比较多,例如线上引用的 JS、CSS 等资源,在文件名后面都会加上一个 hash 值。
用户触发缓存行为
Cache-Control: no-cache
关于缓存的其他知识
这部分与浏览器或许不是很相关
缓存的特征
1. 命中率
衡量缓存是否有效的重要指标
2. 最大元素
能存放缓存的最大个数,超过这个数量,则会触发清空策略
合理设置最大元素值可提高缓存的命中率
3. 清空策略
一些简单的策略:
参考