You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Promise.race是否在首个Promise resolve后忽略其余Promise?

code snippet

核心结论

Promise.race的行为逻辑是:只要传入的所有Promise中,有任意一个率先敲定(无论是resolve成功还是reject失败),Promise.race就会立刻将自身状态同步为这个率先敲定的Promise的状态,其余Promise后续的状态变更不会再对race的返回值产生任何影响,但这些Promise本身不会被暂停或终止,会继续在后台执行直到结束。

你观察到的"无论responsePromise状态如何,timeoutPromise都会执行resolve"是完全符合JS运行逻辑的正常现象,和Promise.race的机制不冲突:

  • 你在构造timeoutPromise的时候,内部的setTimeout回调是同步注册到JS事件队列的,注册动作发生在你调用Promise.race的瞬间,不会因为responsePromise先resolve就自动撤销这个定时器。
  • 如果responsePromise在250ms内率先resolve,race会立刻返回请求结果,但已经注册的定时器不会自动清除,到250ms节点时依然会执行timeoutPromise的resolve逻辑,只是这时候timeoutPromise的结果已经不会被race采纳,相当于空跑一次resolve,不会影响业务逻辑。
  • 如果responsePromise耗时超过250ms,timeoutPromise率先resolve,race就会返回你预设的超时结果,后续responsePromise就算完成也不会被race接收。

代码修正方案

如果你的需求是避免无意义的定时器空跑,或者要在超时后明确抛出错误、中断请求,可以手动增加资源清理逻辑,参考实现:

// 给请求加超时的通用封装
function requestWithTimeout(responsePromise, timeout = 250) {
  let timer = null
  // 超时逻辑建议用reject,方便和正常请求结果做区分
  const timeoutPromise = new Promise((_, reject) => {
    timer = setTimeout(() => {
      reject(new Error(`请求超时,超过${timeout}ms未响应`))
    }, timeout)
  })

  return Promise.race([
    // 请求不管成功失败,只要先敲定就清掉定时器,避免空跑
    responsePromise.finally(() => clearTimeout(timer)),
    timeoutPromise
  ])
}

如果你的请求原生支持AbortController中断信号,还可以在超时触发时主动调用abort方法终止正在进行的请求,彻底避免无效的网络请求消耗资源。


内容的提问来源于stack exchange,提问作者neer2005

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 01:57:11