为何含try/catch的async/await代码仍抛出未捕获错误?
为什么这段代码会抛出未捕获异常?
先看核心代码的执行逻辑:
(async() => { try { let prom = promiseThing(); // 这里立刻执行promiseThing,返回一个rejected的Promise await timeout(); // 等待1秒 await prom; // 1秒后才尝试处理这个rejected Promise console.log("get here"); } catch (err) { console.log(err); } })(); async function promiseThing() { throw new Error("an error"); }
问题根源:Rejected Promise的“悬空”时间
- 当你调用
promiseThing()时,这个异步函数会立即执行,里面的throw会让它返回的Promise直接进入rejected状态。 - 但此时你并没有立刻用
await或者.catch()去处理这个rejected Promise,而是先等待timeout()的1秒延迟。 - JavaScript引擎会监控所有Promise的状态:如果一个Promise变成rejected后,在事件循环的下一轮之前还没有被任何错误处理逻辑绑定,就会触发“未捕获的Promise rejection”错误。
1秒的延迟足够让引擎判定这个rejected Promise没有被处理,所以提前抛出异常,等你后来执行await prom的时候,这个错误已经被引擎报过了,不会再被try/catch捕获。
为什么替换成Promise.resolve()就正常?
如果把await timeout()换成await Promise.resolve(),这个等待会立即完成,几乎没有时间间隔:
promiseThing()返回rejected Promise后,马上就执行到await prom,try/catch会立刻捕获这个rejection,不会出现“悬空”的rejected Promise,自然不会触发未捕获异常。
同理,如果timeout()直接返回Promise.resolve(),也是一样的道理——没有延迟,错误处理逻辑会及时绑定到rejected Promise上。
Promise链的情况为什么一致?
用Promise链写类似逻辑时,比如:
(() => { const prom = promiseThing(); timeout().then(() => { return prom; }).catch(err => console.log(err)); })();
同样会出现未捕获异常:因为prom变成rejected后,要等timeout()的1秒才会进入.then()去处理它,这期间prom的rejection没有被绑定任何错误处理,引擎同样会提前抛出未捕获异常。
内容的提问来源于stack exchange,提问作者Colin Taylor
相关产品推荐
相关产品推荐

