如何理解这段代码中出现的未处理Promise拒绝错误?
为什么这段async函数会抛出未处理的Promise拒绝错误?
先看引发问题的代码:
async function foo() { const p1 = new Promise((resolve) => setTimeout(() => resolve("1"), 1000)); const p2 = new Promise((_, reject) => setTimeout(() => reject("2"), 500)); const results = [await p1, await p2]; // 别这么做!用Promise.all或Promise.allSettled替代 } foo().catch(() => {}); // 尝试捕获所有错误...
你的理解偏差点
你误以为await p1执行完成后才会处理p2,但实际**p2在声明时就已经启动执行了**——Promise的构造函数是同步执行的,里面的setTimeout会立刻被调度。也就是说,p2的拒绝会在p1完成前(500ms后)就触发,而此时await p2的代码还没执行到,p2这个Promise没有被任何await或.catch()绑定处理,自然会触发未处理拒绝错误。
具体执行流程拆解
- 调用
foo()进入函数体:- 同步创建
p1,调度1000ms后resolve的定时器。 - 同步创建
p2,调度500ms后reject的定时器。 - 执行
await p1,foo函数暂停,返回一个pending状态的Promise给外部。
- 同步创建
- 500ms后,
p2的定时器触发,p2被reject,但此时没有任何代码在等待p2——await p2要等到p1resolve(1000ms后)才会执行,所以p2的拒绝此时处于无人处理的状态,Node.js会抛出Uncaught '2'错误。 - 1000ms后,
p1resolve,foo函数恢复执行,开始await p2:此时才把p2的拒绝和foo返回的Promise关联起来,外部的.catch()才会捕获到这个错误,但这已经晚了——p2的拒绝在500ms时已经发生过一次未处理的情况,所以会触发PromiseRejectionHandledWarning,提示拒绝被异步处理了。
正确的并发处理方式
要同时处理多个Promise的并发,应该用Promise.all或Promise.allSettled,它们会在创建时就统一管理所有Promise的状态:
// 用Promise.allSettled获取所有结果(无论成功失败) async function foo() { const p1 = new Promise((resolve) => setTimeout(() => resolve("1"), 1000)); const p2 = new Promise((_, reject) => setTimeout(() => reject("2"), 500)); const results = await Promise.allSettled([p1, p2]); } foo().catch(() => {});
或者如果要在任一Promise拒绝时就终止流程,用Promise.all:
async function foo() { const p1 = new Promise((resolve) => setTimeout(() => resolve("1"), 1000)); const p2 = new Promise((_, reject) => setTimeout(() => reject("2"), 500)); const results = await Promise.all([p1, p2]); } foo().catch(() => {});
这两种方式都会在Promise创建后立刻监听它们的状态,不会出现未处理的拒绝问题。
内容的提问来源于stack exchange,提问作者Géry Ogam
相关产品推荐
相关产品推荐

