为何Promise.catch未捕获部分Promise.then中的异常?示例差异解析
为什么示例1、2的异常能被catch捕获,示例3却不行?
核心逻辑一句话:then方法返回的新Promise状态,完全由回调函数的执行结果决定——要么是回调的返回值(如果是Promise就会“接管”状态),要么是回调抛出的同步异常。只有当异常被关联到当前Promise链上时,后续的catch才能捕获到。
示例1:同步异常被链捕获
f1().then(() => { throw new Error("error from anonymous") }).catch(errorHandler);
f1是async函数,执行后返回一个已resolved的Promise。then的回调里直接同步抛出异常,这个异常会被then返回的新Promise捕获,将其状态置为rejected。这条Promise链的后续catch自然能接住这个rejection。
示例2:async回调的异常被链传递
f1().then(async () => { await f2(); }).catch(errorHandler);
这里的then回调是个async函数:
- f2执行后返回一个rejected的Promise;
- await这个Promise时,会把Promise的rejection转化为同步异常;
- async函数内部的任何异常,都会被自动包装成rejected的Promise,作为
then方法的返回值; - 所以这条Promise链的状态会变成rejected,后续的
catch就能捕获到错误。
示例3:游离的Promise导致异常逃逸
f1().then(() => { f2(); }).catch(errorHandler);
这里的关键是:then的回调里调用了f2但没有返回它的Promise。f2执行后返回的是一个rejected的Promise,但这个Promise完全独立于当前的Promise链(f1().then(...)这条链),没有任何代码把它和链关联起来。它的rejection状态不会传递到当前链的then返回的Promise上,所以后续的catch根本“看不到”这个错误,最终变成未捕获的Promise rejection。
简单说:示例3里的错误属于另一条没人管的Promise链,和你写的catch所在的链没关系,自然抓不到。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

