← 返回题目列表

前端请求去重如何设计?重复点击和并发相同请求怎么处理?

中等 第 18 / 26 题 更新于 2026/07/29
前端网络请求去重并发控制缓存

简化版

前端请求去重是避免同一时间发出多份语义相同的请求。常见方案有按钮禁用、防抖节流、in-flight map 复用同一个 Promise、请求取消、短时间缓存和服务端幂等。设计时要先区分“查询类请求”和“写入类请求”:查询请求可以复用或缓存,写入请求不能简单合并,必须依赖业务幂等键和服务端兜底。

详细版

请求去重的核心是为请求生成稳定 key,例如 method + url + params + body 中影响结果的字段。

场景推荐处理说明
搜索框输入防抖 + 取消旧请求避免无效请求
页面重复加载同接口in-flight 复用多个组件共享结果
按钮重复提交禁用按钮 + 幂等键服务端必须兜底
短时间重复查询TTL 缓存减少后端压力
const pending = new Map<string, Promise<unknown>>()

function requestOnce<T>(key: string, fetcher: () => Promise<T>): Promise<T> {
  if (pending.has(key)) return pending.get(key) as Promise<T>
  const p = fetcher().finally(() => pending.delete(key))
  pending.set(key, p)
  return p
}

去重不是少发请求这么简单,写接口尤其要服务端幂等兜底。

完整版教学

一、为什么会出现重复请求

前端重复请求很常见。用户快速点击按钮,组件重复挂载,路由切换后又回来,多个组件都依赖同一份数据,搜索框每输入一个字符就请求一次,这些都会制造重复流量。

重复请求带来的问题包括浪费带宽、后端压力增加、页面状态被旧响应覆盖,以及写接口重复提交。

二、先区分读请求和写请求

读请求一般没有副作用,比如查询列表、获取详情、拉配置。它们适合复用、缓存和合并。

写请求有副作用,比如创建订单、提交表单、支付确认。它们不能只靠前端合并,必须由后端按业务 idempotency key 保证幂等。

三、in-flight 复用

in-flight 表示请求已经发出但还没完成。如果同一个 key 的请求再次出现,就返回同一个 Promise。

function buildKey(url: string, params: Record<string, unknown>) {
  return `${url}?${new URLSearchParams(params as Record<string, string>)}`
}

请求完成后要从 map 中删除,否则会变成永久缓存。

四、请求 key 怎么设计

key 设计决定去重是否正确。

字段是否常纳入 key
method
url/path
query params
body写请求谨慎
auth user多用户场景要考虑
headers影响结果时纳入

如果 key 太粗,会把不同请求错误合并;key 太细,则去重效果差。

五、和缓存的区别

in-flight 去重只复用“正在进行”的请求;缓存则复用“已经完成”的结果。

缓存需要 TTL、失效和刷新策略。去重通常不需要长期保留结果,只要请求结束就释放。

六、写请求要靠幂等

重复提交订单不能只靠按钮 disabled,因为用户可以刷新、重试、脚本请求或网络层重放。

写接口应带业务幂等键:

fetch('/api/order', {
  method: 'POST',
  headers: { 'Idempotency-Key': orderDraftId }
})

后端用这个 key 判断是否已经处理过。

七、常见误区与追问

  • 误区:前端禁用按钮就能防重复提交。 用户可以绕过页面或网络重试,后端必须做幂等。
  • 误区:所有相同 URL 请求都能合并。 query、body、用户身份和 header 可能影响响应。
  • 误区:pending map 不清理也没关系。 不清理会造成内存增长和结果长期复用错误。
  • 追问:请求失败后 pending 怎么办? 使用 finally 删除 key,让后续请求可以重新发起。
  • 追问:读请求和写请求去重有什么区别? 读请求可复用结果,写请求要依赖幂等键和业务状态。
  • 追问:多个组件请求同一接口怎么优化? 共享请求层或数据层,用 in-flight map 复用 Promise。

八、加强记忆

请求去重记成“同路请求共坐一班车”。读请求可以合并和缓存,写请求要幂等;key 要准,pending 要清,旧响应不能乱覆盖新状态。