在前端开发中,性能优化是绕不开的话题,而 缓存(Cache) 则是性能优化中最具性价比的一环。本文从基础概念出发,带你深入理解 浏览器缓存的工作机制 ,尤其是 强缓存 与 协商缓存 的原理、应用场景与配置方法。
一、什么是 Cache?
Cache,简单来说就是"存副本的地方"。
- 副本:不是源数据本身,而是拷贝或计算结果。
- 临时性:有有效期或失效策略。
- 高效性:读取速度更快,或减少网络请求和计算资源。
Cache 无处不在,比如浏览器缓存、CDN 缓存、服务器端缓存、应用层缓存,甚至硬件层缓存。本文我们聚焦前端最常打交道的 浏览器缓存。
二、浏览器缓存的三种类型
浏览器缓存主要分为三类:
- 强缓存 (
Cache-Control
/Expires
) - 协商缓存 (
ETag
/Last-Modified
) - Service Worker 缓存(适用于 PWA)
我们先从最基础的 强缓存 和 协商缓存 入手。
三、强缓存(Strong Cache)
1. 核心特点
在缓存有效期内,浏览器直接使用本地缓存文件,不会请求服务器。这让页面加载飞快,并且大幅减少服务器压力。
2. 实现原理
当浏览器请求某个资源时,若响应头中带有 Expires
或 Cache-Control
,浏览器会记住缓存策略,在有效期内直接使用本地副本。
(1) Expires(HTTP/1.0)
yaml
Expires: Wed, 25 Aug 2025 08:30:00 GMT
- 表示资源的绝对过期时间。
- 缺点:依赖客户端时间,时间不准会导致缓存失效。
(2) Cache-Control(HTTP/1.1 推荐)
arduino
Cache-Control: public, max-age=600
-
表示资源在 600 秒内走强缓存。
-
常见指令:
max-age=xxx
:资源缓存时长(秒)no-store
:不缓存no-cache
:强制协商缓存public
/private
:是否允许代理服务器缓存
3. 工作流程
- 浏览器请求资源
- 服务器返回带缓存头的响应
- 下次访问时,直接读取本地缓存,不请求服务器
4. 优缺点
优点 | 缺点 |
---|---|
加载速度最快 | 内容更新不及时,可能命中过期资源 |
减少服务器压力 | 需配合版本控制才能避免脏缓存 |
四、协商缓存(Negotiated Cache)
1. 核心特点
每次请求都会问服务器:"文件有更新吗?"
- 没更新 → 服务器返回
304 Not Modified
,浏览器用本地缓存。 - 有更新 → 返回新文件并更新缓存。
2. 实现方式
方式一:Last-Modified / If-Modified-Since
首次请求:
yaml
Last-Modified: Sun, 24 Aug 2025 10:00:00 GMT
二次请求:
yaml
If-Modified-Since: Sun, 24 Aug 2025 10:00:00 GMT
缺点:
- 精度是秒,秒级内多次更新无法区分。
- 动态文件更新时间变化容易导致缓存失效。
方式二:ETag / If-None-Match
首次请求:
vbnet
ETag: "abc123xyz"
二次请求:
sql
If-None-Match: "abc123xyz"
优点:
- 精确到字节,命中率高。
缺点: - 生成 ETag 有一定计算开销。
3. 工作流程
- 浏览器带标识请求资源。
- 服务器检查标识是否匹配。
- 返回
304
或200
,并更新缓存。
五、强缓存 vs 协商缓存
特性 | 强缓存 | 协商缓存 |
---|---|---|
是否请求服务器 | 否 | 是 |
加载速度 | 极快 | 略慢 |
更新实时性 | 较差 | 更好 |
适用场景 | 静态资源 | 实时更新数据 |
六、最佳实践
-
静态资源文件:加 hash 文件名 + 强缓存
arduino/static/js/app.abc123.js
-
频繁更新的接口数据:使用协商缓存
-
结合 CDN:进一步提升加载速度
七、总结
- 强缓存:速度最快,但要注意失效策略。
- 协商缓存:更实时,适合更新频繁的内容。
- 混合策略:强缓存 + 协商缓存 + 文件版本控制,是目前最常见的最佳实践方案。
掌握这些知识,不仅能帮你优化前端性能,还能降低服务器成本,打造更加丝滑的用户体验。