嵌套Promise与catch块异常捕获疑问:无内部catch时外层不触发?
这确实是 JavaScript Promise 机制的预期行为,核心原因和你代码里 Promise 链的关联性以及错误传递规则有关,我给你拆解清楚:
核心前提:你的内部 Promise 链是独立的
先看你的代码结构:在 printInfo() 的 then 回调里,你发起了 worksheet.applyFilterAsync() 并构建了一个新的 Promise 链,但你没有把这个内部链 return 出去。这意味着这个内部链和外层的 printInfo() 链是完全独立的两个 Promise 流,外层链不会感知到内部链的状态变化(成功/失败)。
情况1:没有内部 catch 块
当 applyFilterAsync 执行出错时,错误会依次触发后续 then 的 reject 回调(每个回调里都抛出了新的 Error),但因为这个内部链没有被 return 给外层链,且没有自己的 catch 处理,这个错误会变成未处理的 Promise 拒绝(Unhandled Promise Rejection)。而外层的 printInfo() 链在 then 回调执行完毕后,已经处于 resolved 状态(因为回调没有返回任何 Promise,默认返回一个 resolved 的空 Promise),所以最外层的 catch 块完全不会被触发。
情况2:有内部 catch 块
你看到最外层 catch 执行,本质是因为内部 catch 处理错误后重新抛出了错误,同时你可能把内部链 return 给了外层链(或者你的实际测试代码里有 return 操作)。当内部 catch 捕获错误并重新抛出时,内部链会变成 rejected 状态;如果这个内部链被 return 到外层的 printInfo() 链中,那么这个 rejected 状态就会向上传递,最终触发最外层的 catch 块。
如果你的内部 catch 是空的(比如代码里的注释那样),理论上内部链会在 catch 后变成 resolved 状态,外层 catch 不会执行——所以你看到的现象大概率是内部 catch 里实际有重新抛出错误的逻辑,或者你在代码里不小心 return 了内部链。
怎么让内部错误总能触发最外层 catch?
如果你希望内部链的错误不管有没有内部 catch,都能传递到最外层 catch,只需要把内部链 return 出去:
printInfo(filter, counter).then(function(result) { let worksheet = tableauViz.getWorkbook().getActiveSheet().getWorksheets().get('Filter'); // 关键:return 这个内部 Promise 链 return worksheet.applyFilterAsync('test', ['hello', 'world'], 'replace').then(promiseTimeout(filter.delay, counter), function(err) { throw new Error(err); }).then(function(counter) { //more processing }, function(err) { throw new Error(err); }).catch(function(resp){ // inner catch // 如果需要让错误继续传递到外层,在这里重新抛出 throw resp; }); }, function(err) { throw new Error(err); }).catch(function(resp){ // outer most catch console.error('in catch block'); console.error(resp); });
这样,内部链的状态就会合并到外层链中,错误可以正常向上传递。
内容的提问来源于stack exchange,提问作者opensource-developer

