异步请求竞态导致页面状态错乱,需通过Network面板验证后发起请求先返回现象;可用AbortController取消旧请求、请求ID匹配响应或迁移到useQuery等方案解决。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

当你用Codex生成异步请求逻辑后,页面状态与用户当前筛选条件不一致,比如点完「已完成」却显示「进行中」的数据,说明异步执行顺序已被打乱。
确认是否发生竞态条件
打开浏览器开发者工具 → 切换到 Network 面板 → 勾选「Preserve log」→ 重复快速切换两个筛选项(如「全部」→「待处理」→「已完成」)→ 观察对应接口的发起时间(Initiator 列)和响应时间(Time 列)。
如果发现后发起的请求反而先返回,且其响应数据覆盖了前一个请求的结果,就坐实了竞态条件。这一步不能跳过,因为很多“状态错乱”其实是缓存或本地状态未清导致,不是真正的竞态。
用 AbortController 主动取消旧请求
方法一:在每次新请求发起前,调用上一个控制器的 abort() 方法。
在组件顶层声明一个 ref:const controllerRef = useRef
每次调用 API 前先清理旧控制器:【controllerRef.current?.abort(); controllerRef.current = new AbortController();】,再把 signal: controllerRef.current.signal 传给 fetch 或 axios。
注意:axios 1.7+ 才原生支持 AbortSignal;若用旧版,需通过 CancelToken 兼容,但 CancelToken 已废弃,不建议新项目采用。
用请求 ID 实现响应匹配
第一步:为每次请求生成唯一 ID,例如使用 crypto.randomUUID() 或时间戳 + 序号组合。
通过 codex-reset-radar.pages.dev 监控 Codex 使用重置窗口。轮询 current.json,检测窗口开启/关闭、预测等级变化以及概率跳变。
第二步:将该 ID 同时注入请求参数(便于后端日志追踪)和本地状态(如 setPendingRequestId(id))。
第三步:响应到达后,先比对当前 pending ID 是否等于本次响应 ID:if (id !== pendingRequestId) return;,仅当匹配才执行 setList(data)。
这招不依赖网络层控制,纯前端兜底,适合无法修改请求发起逻辑的遗留代码。但必须确保 ID 生成足够唯一——用 Date.now() 单独拼接在高并发下可能重复,【务必加入随机因子或递增序号】。
改用 useQuery 等成熟数据加载库
方法一:直接迁移到 TanStack Query(React Query)的 useQuery。
它默认开启请求去重与自动取消,只要 queryKey 包含 filter 值(如 ['tasks', filter]),切换 filter 时旧请求会自动被标记为 stale 并取消,新请求结果不会错误覆盖。
方法二:若暂不能引入新库,可手写简易版「请求快照」逻辑——在发起请求时记录当前 filter 值,在响应回调里比对,不一致则丢弃。










