fetch错误处理:慢网络场景下如何避免.catch触发后调用.then?
现象原因说明
你观察到的catch和then先后触发的行为不符合fetch的Promise设计逻辑,标准Promise一旦决议为成功/失败状态就会永久凝固,不可能同时触发两个回调。
你遇到的现象本质是代码被触发了两次:慢网络下操作未及时反馈,用户大概率重复触发了请求动作,第一次请求超时走了catch打印error,第二次请求成功走了then打印success,后端日志中查到的成功请求对应第二次调用,第一次超时请求可能因为未到达后端没有留下日志。
规避方案
可以从防止重复触发、加超时控制两个维度处理:
- 操作入口加防抖/节流,短时间内重复触发的相同操作只执行一次
- 加全局请求锁,同一请求未完成时屏蔽后续相同请求
- 给fetch添加手动超时逻辑,超时后直接中断请求,避免挂起的请求后续意外返回执行逻辑
代码实现示例
// 全局请求锁标记 let isRequesting = false function handleErrors(response) { if (!response.ok) { throw Error(response.statusText); } return response; } // 封装带超时的fetch方法 function fetchWithTimeout(url, options = {}, timeout = 8000) { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); return fetch(url, { ...options, signal: controller.signal }).then(res => { clearTimeout(timeoutId); return res; }) } // 实际调用逻辑 if (!isRequesting) { isRequesting = true; fetchWithTimeout("http://url", {}, 10000) .then(handleErrors) .then(() => console.log("success")) .catch(() => console.log("error")) .finally(() => { // 请求完成后重置锁 isRequesting = false; }) }
额外说明:单页应用场景下,还可以在路由切换、组件卸载时调用AbortController.abort()取消未完成的请求,避免页面销毁后请求返回触发多余逻辑。
内容的提问来源于stack exchange,提问作者Fusscreme
相关产品推荐
相关产品推荐

