NodeJS中添加错误处理器仍出现未捕获异常的原因
NodeJS异步错误处理:为何已捕获的Promise错误仍会触发未捕获异常?
先看你提供的代码:
function logMsgWithCurrentTime(message) { console.log(`${message}--${new Date().getTime()}`); } function resolveOrRejectAfter1Seconds(success) { return new Promise((resolve, reject) => { setTimeout(() => { if (success) { resolve('resolved after 1 second'); } else { reject(new Error('raw ex')); } }, 1000); }); } async function asyncCall() { logMsgWithCurrentTime('main calling'); const asyncP = resolveOrRejectAfter1Seconds(false); asyncP .then(_ => logMsgWithCurrentTime(_)) .catch(err => { logMsgWithCurrentTime(`Caught err ${err.message}`); err.message = 'Sanitized'; }); logMsgWithCurrentTime('beforeAwait'); await asyncP; logMsgWithCurrentTime('afterAwait'); logMsgWithCurrentTime('main done'); } asyncCall();
现象分析
程序执行后,控制台会先打印Caught err raw ex,但随后会抛出一条Sanitized的未捕获异常,且afterAwait和main done永远不会执行。
核心原因
- Promise状态不可变:
asyncP是resolveOrRejectAfter1Seconds(false)返回的Promise,它的状态是已拒绝,这个状态一旦确定就无法修改。 .catch()返回新Promise:你给asyncP链式调用.then().catch(),这个操作会生成一个全新的Promise,而非修改原asyncP的状态。原asyncP仍然保持拒绝状态。await会触发拒绝Promise的错误抛出:当你await一个拒绝状态的Promise时,JS会将该Promise的拒绝原因作为错误抛出。由于asyncCall函数中没有用try/catch包裹这个await,错误会向上冒泡,成为未捕获异常。- 错误对象是引用类型:你在
catch中修改的err是原Promise拒绝时抛出的同一个错误对象,所以await抛出的错误也会是这个被修改后的对象,导致控制台显示Sanitized。
两种解决方法的原理
将链式调用结果赋值给
asyncP:const asyncP = resolveOrRejectAfter1Seconds(false).then(...).catch(...);此时
asyncP指向的是.catch()返回的新Promise。因为catch已经处理了原错误,这个新Promise的状态是已完成(resolved),await asyncP不会抛出错误,程序会正常执行后续代码。移除
await asyncP语句:
没有await的触发,原拒绝状态的Promise不会主动抛出错误,自然不会产生未捕获异常。
内容的提问来源于stack exchange,提问作者Xin Zhang
相关产品推荐
相关产品推荐

