浅析ServiceWorker缓存与HTTP缓存对比了解
虽然 ServiceWorker 和 PWA 正在成为现代 Web 应用程序的标准,但浏览器资源缓存变得比以往任何时候都复杂。本文涵盖了浏览器缓存的重点内容,具体包括:
- ServiceWorker 缓存与 HTTP 缓存的优先级?
- 主流浏览器实现的 MemoryCache 和 DiskCache 在哪一层?
- MemoryCache、DiskCache、ServiceWorker 缓存哪个速度更快?
一、缓存流程概述
我们先来看标准定义的资源请求遵循的顺序:

1、ServiceWorker 缓存:ServiceWorker 检查资源是否存在其缓存中,并根据其编程的缓存策略决定是否返回资源。这个操作不会自动发生,需要在注册的 ServiceWorker 中定义 fetch
事件去拦截并处理网络请求,这样才能命中 ServiceWorker 缓存而不是网络或者 HTTP 缓存。
2、HTTP 缓存:这里就是我们常常说的「强缓存」和「协商缓存」,如果 HTTP 缓存未过期的话,浏览器就会使用 HTTP 缓存的资源。
3、服务器端:如果 ServiceWorker 缓存或者 HTTP 缓存中未找到任何资源,则浏览器会向网络请求资源。这里就会涉及到 CDN 服务或者源服务的工作了。
这是标准定义的资源请求流程,但是有追求的浏览器还会在 ServiceWorker 上面加一层 「内存缓存层」 ,以 Chrome 为例,我们请求一个资源,除去网络,会有三种浏览器缓存返回:
那么 MemoryCache 和 DiskCache 与 ServiceWorker Cache 的优先级是怎么样的呢?下面我们讲讲三者的区别。
二、MemoryCache、DiskCache 在缓存流程的哪一层
我们以 Chrome 为例,MemoryCache 作为第一公民,位于 ServiceWorker 之上。也就是命中了 MemoryCache,就不会触发 ServiceWorker 的 fetch 事件。而 DiskCache 则位于原来的 HTTP 缓存层:

MemoryCache 的存在会导致一个问题: ServiceWorker 并不总是对资源有着控制权。 这会另我们本来期望的情况会变得复杂且不可预知。可惜的是 MemoryCache 并不在 W3C 的标准中,W3C 从 2016 年到现在仍然在讨论着这个事情,看来短时间这个问题是得不到解决了。
我们真的没有办法么?要是我们遇到业务场景,确实对 ServiceWorker 资源控制权有很强的的要求,我们还是可以做点事情的。
MemoryCache 是受控于 「强缓存」 的,这意味着我们可以在 ServiceWorker 拦截资源的响应,并设置资源响应头来使资源从 MemoryCache 失效:
cache-control: max-age=0
self.addEventListener("fetch", (event) => {
event.respondWith(
(async function () {
// 从 HTTP 缓存或者网络获取资源
const res = fetch(event.request);
// 因为 Response 是一个流,只能用一次,所以这里要 clone 一下。
const newRes = res.clone();
// 改写资源响应头
return new Response(res.body, { ...newRes, headers: {
'cache-control': 'max-age=0'
}});
})();
);
});
需要注意的是,这种方法是以牺牲少量加载性能为前提的。这取决于我们实际场景中是性能优先,还是离线优先,或者其他什么情况优先。
三、MemoryCache、DiskCache、ServiceWorker 缓存哪个速度更快?

我们再看一下同一个资源三种缓存的加载速度和优先级:
(1)加载速度:MemoryCache > DiskCache > ServiceWorker
(2)优先级:MemoryCache > ServiceWorker> DiskCache
MemoryCache 优先级在 ServiceWorker 前面,这个没问题。
但是速度更慢的 ServiceWorker 优先级比速度更快的 DiskCache 更高?那盘下来,ServiceWorker 岂不是减慢了站点的加载速度?
实验对比:详见原文,这里记录下结论
1、在少量资源并发的时候,DiskCache 更快
2、在大量资源并发的时候,ServiceWorker 更快
3、那 DiskCache 和 ServiceWorker 怎么选择? 都要
由于 ServiceWorker 的优先级在 DiskCache 之上,我们可以在 ServiceWorker 进行 「资源竞速」,同一时间请求 ServiceWorker Cache 和 DiskCache,哪个先返回就把资源返回上一层。代码可能是这样的:使用 Promise.race()
self.addEventListener("fetch", (event) => {
event.respondWith(
(async function () {
const res = Promise.race([
// 请求 ServiceWorker Cache
cache.open(CACHE_NAME).then(cache => cache.match(event.request)),
// 请求 DiskCache 或者网络资源
fetch(event.request)
])
})();
);
});
总结:
本篇我们搞懂了 ServiceCache、MemoryCache、DiskCache 的优先级,然后深入对比了 ServiceWorker Cache 和 DiskCache 的性能表现:在少量资源并发的时候,DiskCache 更快,在大量资源并发的时候,ServiceWorker 更快。最后通过「资源竞速」的方式来兼顾两种情况。
学习链接:https://juejin.cn/post/7088741970696208414
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2017-11-23 ES6里关于函数的拓展(三)
2017-11-23 ES6里关于函数的拓展(二)