Node.js Promise异步问题:为何reject未终止执行而throw可以?
先贴出问题里的代码:
new Promise(async (resolve, reject) => { try { await new Promise((resolveSec, rejectSec) => { setTimeout(function() { resolveSec('') }, 1000); }).then(function(val) { return reject('should reject') //不会终止执行 //throw('should reject'); //会终止执行 }); console.log('not here'); //本不应执行到此处 } catch (err) { console.log('caught error'); } }).catch(function(err) { console.log(err); });
核心原因是你调用的reject属于最外层的Promise,而非当前await的Promise链,具体拆解如下:
先理清各个Promise的关系:
最外层有一个Promise(我们叫它P1),它的执行器是async函数;内部await的是「new Promise(...)(叫它P2)的then回调返回的新Promise」(叫它P3)。当你在then回调里写
return reject('should reject')时:
这个reject是P1的reject方法,调用它只会把P1标记为rejected状态,但完全不影响P3的状态——因为then回调本身是正常执行的(只是调用了另一个Promise的reject,没有抛出错误,也没有返回rejected的Promise),所以P3会变成fulfilled状态。await等待的是P3,所以await顺利完成,代码继续执行到console.log('not here')。之后P1的rejected状态会触发最外层的catch,输出should reject。当你换成
throw('should reject')时:
throw会让then回调抛出异常,根据Promise的规则:如果then/catch回调里抛出异常,那么该回调返回的Promise(也就是P3)会直接变成rejected状态。这时候awaitP3就会抛出这个异常,被内部的try/catch捕获,所以代码不会执行到console.log('not here'),而是进入try块的catch,输出caught error。同时因为异常已经被内部捕获,最外层的catch不会被触发。
简单来说:你调用的reject是另一个Promise的“终止开关”,而throw才是当前await的Promise链的“终止信号”。
内容的提问来源于stack exchange,提问作者dfilkovi

