核心思路是用 Map 缓存进行中的 Promise 以避免重复请求:一、请求标识需唯一,组合方法+路径+序列化参数;二、Map 存 Promise 而非结果,自动解决竞态;三、加时间戳控制有效期(如10秒);四、限制 Map 容量防内存泄漏。

核心思路是用 Map 当作内存缓存池,把相同请求标识(如 URL + 参数)作为 key,把正在进行的 Promise 作为 value。后续相同请求不发新网络调用,而是直接复用这个 Promise,等它 resolve 后统一返回结果。
一、请求标识必须精准唯一
防抖是否生效,关键在 key 是否能准确区分“该不该合并”。不能只用 URL,否则不同参数的请求会被误判为重复。
- 推荐组合:HTTP 方法 + 请求路径 + 序列化后的请求体(GET 用 query 参数,POST/PUT 用 data)
- 示例:
GET /api/user?id=123和GET /api/user?id=456必须生成两个不同 key - 避免直接拼接对象:用
JSON.stringify(data)或更健壮的深比较函数(如 lodash 的isEqual)
二、Map 存的是 Promise,不是响应数据
缓存的不是最终结果,而是“正在执行的请求任务”。这样能天然解决并发请求的竞态问题,所有等待者共享同一结果。
- 首次请求:发起真实网络调用,将返回的 Promise 存入 Map
- 重复请求:直接返回已存的 Promise,不触发新 fetch
- 请求完成:自动从 Map 中清理对应 key,防止内存堆积
三、加时间窗口控制有效期
纯 Map 缓存没有过期机制,容易返回陈旧数据。建议搭配时间戳做轻量级时效管理。
- 每个 entry 可以存一个对象:
{ promise, timestamp } - 读取时判断
Date.now() - timestamp < 10000(比如 10 秒内有效) - 超时则丢弃旧 Promise,发起新请求并更新 Map
四、注意内存泄漏防护
长期运行的单页应用中,Map 不清理会导致内存持续增长。
- 设置最大容量上限(如 500 条),超出时清空最老的几条
- 不用 LRU 复杂结构,简单轮询 +
Map.keys().next()删除头项即可 - 对高频接口可按业务维度加前缀隔离,比如
user::getById:123,便于定向清理

















