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

JavaScript中Promise已加Catch仍触发Uncaught错误的问题

Promise错误无法被外层try/catch捕获的问题分析与解决

问题场景

在JavaScript中调用外部API时,尝试用外层try/catch捕获Promise异步操作的错误,但控制台仍抛出Uncaught (in promise) Error: Error,无法触发预期的doSomethingElse()。复现代码如下:

外层调用代码:

try {
    functionGeneratingTheError();
} catch (error) {
    doSomethingElse();
}

异步请求函数:

function functionGeneratingTheError() {
    
    var getTokenCallPayload = {
        "client_id" : clientId,
        "client_secret" : clientSecret,
        "refresh_token" : refreshToken,
        "grant_type" : "refresh_token"
    };
    var getTokenCallOptions = {
        "method" : "POST",
        "body" : JSON.stringify(getTokenCallPayload),
        "muteHttpExceptions" : false
    };
    fetch(tokenURL, getTokenCallOptions)
    .then(response => {
        if (response.ok) {
            return response.json();
        } else {
            throw new Error("Error");
        }
    })
    .then(data => {
        doSomething();
    })  
    .then(response=> {
        doSomethingAgain();
    }) 
    .catch(error => {
        throw error;
    });
}

问题原因

  1. 同步try/catch无法捕获异步错误:外层try/catch是同步代码,而fetch是异步操作,异步代码的错误会在事件循环的后续阶段抛出,此时同步的try/catch已经执行完毕,无法捕获该错误。
  2. 内部catch重新抛出未处理的错误:Promise链中的catch虽然捕获了错误,但又通过throw error重新抛出,且没有后续代码处理这个抛出的错误,导致浏览器提示未捕获的Promise错误。
  3. 直接调用doSomethingElse()会触发后续then报错:如果在内部catch直接调用doSomethingElse(),Promise链不会中断,后续的.then会继续执行,因缺少data参数而报错。

解决方案

方案一:使用async/await配合外层try/catch

让异步函数返回Promise,在外层用async/await将异步操作转为同步写法,这样try/catch就能捕获异步错误。

修改后代码:

// 外层处理函数改为async函数
async function handleFormSubmit() {
    try {
        await functionGeneratingTheError();
    } catch (error) {
        doSomethingElse();
    }
}

function functionGeneratingTheError() {
    var getTokenCallPayload = {
        "client_id" : clientId,
        "client_secret" : clientSecret,
        "refresh_token" : refreshToken,
        "grant_type" : "refresh_token"
    };
    var getTokenCallOptions = {
        "method" : "POST",
        "body" : JSON.stringify(getTokenCallPayload),
        "muteHttpExceptions" : false
    };
    // 返回Promise链,让外层await能捕获错误
    return fetch(tokenURL, getTokenCallOptions)
    .then(response => {
        if (response.ok) {
            return response.json();
        } else {
            throw new Error("Error");
        }
    })
    .then(data => {
        doSomething();
    })  
    .then(response=> {
        doSomethingAgain();
    });
}

方案二:在内部Promise链的catch中直接处理错误

去掉内部catch的throw error,直接在catch中执行doSomethingElse(),同时如果需要中断后续链式调用,可以返回Promise.reject()(若有后续链),或直接终止:

function functionGeneratingTheError() {
    var getTokenCallPayload = {
        "client_id" : clientId,
        "client_secret" : clientSecret,
        "refresh_token" : refreshToken,
        "grant_type" : "refresh_token"
    };
    var getTokenCallOptions = {
        "method" : "POST",
        "body" : JSON.stringify(getTokenCallPayload),
        "muteHttpExceptions" : false
    };
    fetch(tokenURL, getTokenCallOptions)
    .then(response => {
        if (response.ok) {
            return response.json();
        } else {
            throw new Error("Error");
        }
    })
    .then(data => {
        doSomething();
    })  
    .then(response=> {
        doSomethingAgain();
    }) 
    .catch(error => {
        // 直接处理错误,不再抛出
        doSomethingElse();
        // 若需明确中断后续可能的链式调用,可返回rejected Promise
        // return Promise.reject(error);
    });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 03:45:53