为什么async修饰Promise执行器时reject无法捕获request抛出的错误
问题原理说明
核心原因拆解
- 首先明确request 2.88版本的参数校验逻辑:当传入的url/uri参数非法或者缺失时,参数校验逻辑是同步执行的,会直接抛出同步异常,不会走到后续发送请求、触发
error事件的流程,你代码中绑定error事件的代码根本没有执行机会。 - 其次明确Promise构造器的执行规则:传入Promise构造器的执行器函数如果是普通同步函数,执行过程中抛出的所有同步异常,都会被Promise构造器自动捕获,直接将当前Promise置为rejected状态,所以不加async时错误能被正常捕获。
- 最后明确async函数的异常处理规则:如果给执行器加上
async关键字,执行器就变成了异步函数,异步函数内部抛出的所有同步异常,都会被async的隐式包装层直接捕获,转换为这个async函数自身返回的Promise的rejected状态,这个异常不会向外抛到Promise构造器。
为什么会出现UnhandledPromiseRejectionWarning
因为async执行器返回的隐式Promise被拒绝后,没有任何代码处理这个拒绝状态:
- 你new出来的外层Promise既不会收到构造器自动捕获的异常,也不会触发你绑定的
error事件回调(因为request同步抛错时事件绑定代码还没执行),所以外层Promise不会被reject - async执行器自己返回的隐式Promise被拒绝,且没有被任何catch处理,就触发了未处理Promise拒绝的警告
常见误区纠正
你猜测的「request抛出异常的时机早于reject触发」不成立,本质是异常的捕获链路被async关键字截断了,根本没有走到你写的reject逻辑,也没有走到Promise构造器的自动reject逻辑。
推荐修复方案
- 直接移除执行器前的async关键字:你的代码中没有用到await语法,加async完全没有必要,移除后就能让Promise构造器正常捕获request抛出的同步异常
- 如果确实需要在执行器中使用await,必须添加try/catch手动捕获同步异常:
return new Promise(async (resolve, reject) => { try { request({uri: url}).on('error', err => { reject(err); }).on('response', response => { resolve(response); }); } catch (err) { // 手动捕获request抛出的同步异常 reject(err); } });
内容的提问来源于stack exchange,提问作者yaro
相关产品推荐
相关产品推荐

