JavaScript中基于回调的fetch实现无法正常返回response与catch捕获错误的问题
修复带回调的fetch登录函数无法正常获取全流程值的问题
现有实现的核心问题
- 回调触发逻辑分散,同一次请求会多次执行回调,后一次调用的参数会覆盖前一次的输出:
- 拿到原始response时第一次调用回调,传递第三个位置值为response
- 解析完成data后第二次调用回调,传递第一个位置值为data
- 两次连续触发回调,控制台最终只会留下最后一次的输出,第一次传递的response值根本无法保留
- 参数传递错位:第一个then分支把response传到了第三个参数位(对应定义的回调签名里的error位置),哪怕第一次回调执行,也会把response识别为error值
- 受fetch原生特性影响,错误捕获存在天然漏洞:只有网络层面的请求失败(域名解析失败、跨域拦截、断网)才会进入catch分支,服务器返回404、500这类HTTP状态错误时,fetch不会自动触发catch,容易出现错误漏判的情况
- 原代码中
console.log(login(...))的写法无实际意义:login函数本身没有返回值,这行打印结果永远是undefined,和回调传递的业务值无关
修复方案
核心调整思路:把请求全流程要获取的三个值统一存在局部变量中,等Promise链执行到终点(不管成功、失败),一次性把收集到的值传给回调,避免多次触发回调导致的值被覆盖。
const login = function(cb) { // 定义局部变量统一收集全流程的三个目标值 let rawResponse = null; let parsedData = null; let caughtError = null; fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => { // 拿到原始response先存值,不直接触发回调 rawResponse = response; return response.json(); }) .then((data) => { // 拿到解析后的data存值 parsedData = data; }) .catch((e) => { // 捕获到请求异常后存值 caughtError = e; console.log('error inside catch:', e.message) }) .finally(() => { // 无论成功还是失败,都把收集到的三个值一次性传给回调 cb(parsedData, rawResponse, caughtError); }) } // 测试调用:无论请求成功还是触发异常,都能一次性拿到完整的三个值 login((data, response, err) => console.log('data', data, 'response', response, 'error', err))
补充优化
如果需要覆盖HTTP状态类的错误场景(比如404、500),可以在拿到原始response后手动判断状态码,抛出错误让catch分支捕获:
.then((response) => { rawResponse = response; // 状态码非2xx时手动抛出错误 if (!response.ok) { throw new Error(`请求失败,状态码:${response.status}`) } return response.json(); })
内容的提问来源于stack exchange,提问作者Asking
相关产品推荐
相关产品推荐

