超时 Promise 必须用 reject 触发,确保 race 状态为 rejected 以便 catch 明确捕获;每次请求需新建独立 timeout 实例;应自定义 TimeoutError 类并用 instanceof 判断;配合 AbortController 中断 fetch 请求,abort 后统一转为 TimeoutError。

超时 Promise 必须用 reject 触发
如果定时器 Promise 用 resolve,race 会提前返回 undefined 或空值,掩盖真实错误,导致业务逻辑误判。正确做法是只在定时器中调用 reject,确保 race 状态为 rejected,让 catch 能明确捕获超时分支。
每次请求都新建 timeout Promise
复用同一个定时器 Promise 会导致状态残留或多次触发异常。应确保每个请求都生成独立的 timeout 实例:
- 避免在函数外定义并重复传入 timeout Promise
- 封装函数内部创建 new Promise + setTimeout,不缓存 timer 变量
- 防止因前序请求未完成而干扰当前 race 判定
区分超时错误与其他错误类型
仅靠 err.message === 'Request timed out' 容易被服务端返回的同名错误干扰。更稳妥的方式是:
- 自定义
TimeoutError类,继承Error并设置唯一name(如'TimeoutError') - 在 catch 中用
err instanceof TimeoutError判断,而非字符串匹配 - 超时错误信息里带上毫秒数(如
'Timeout: 5000ms'),便于定位配置问题
配合 AbortController 真正中断网络请求
Promise.race 只控制 Promise 状态,不终止底层 fetch 请求。若不干预,超时后请求仍在后台运行,浪费连接与带宽:
- 创建
AbortController实例,将signal传入 fetch 配置 - 在超时 Promise 的
setTimeout回调中调用controller.abort() - 注意:abort 后 fetch 会抛出
AbortError,需在 catch 中统一转为TimeoutError,保持错误语义一致










