为什么 promise reject 不处理错误

Why promise reject does not handle an error

我正在使用节点 v10.24.1

的 nodejs request 包(2.88 版本)

如果没有指定 url,下面的 Promise 不会处理错误。我得到 UnhandledPromiseRejectionWarning 并且从 request package 来源我可以看到针对该情况抛出的异常。

如果我删除 async 关键字,一切正常,并且拒绝处理。

return new Promise(async (resolve, reject) => {
   request(uri: url).on('error', err => {
      reject();
   }).on('response', response => {
      resolve();
   });
});

你能解释一下发生了什么吗?可能请求的异常在实际触发拒绝之前完成。请提供任何详细信息。

当您将一个函数传递给 new Promise 时,此函数会立即 执行。

这里没有魔法,为了说明的目的,new Promise() 的构造函数可能看起来有点像这样:

class Promise {
  constructor(executor) {
    executor(this.resolveFunction, this.rejectFunction); 
  }
}

所以这个例子:

new Promise(() => {
  console.log(1);
});
console.log(2);

输出:

1
2

这很重要,因为如果您将某些东西传递给 new Promise 并引发异常,这也会立即发生:

new Promise((res, rej) => {
  throw new Error('foo');
});

这里抛出的错误不会导致 promise 被拒绝,它完全阻止了 new Promise() 成功。没有返回承诺,并且在调用 new Promise().

outer 函数中抛出异常

但是,当您传递一个异步函数时,这会崩溃:

new Promise(async (res, rej) => {
  throw new Error('foo');
});

由于异步函数的工作方式,此错误将 不会 new Promise() 的设置期间抛出,但您传递的异步函数将异步处理错误并且returns 一个被拒绝的承诺,new Promise() 不知道如何处理。

这和自己直接调用异步函数,不处理错误没什么区别:

(async () => {
  throw new Error('foo');
})();

所以事情失败的原因与 new Promise() 关系不大,但更多的是与异步函数的一般工作方式有关。

这是对未来读者的最后一次提醒,您永远不应将 async 执行程序传递给 new Promise(),因为:

  • 你需要 async 的唯一原因是你可以使用 await.
  • await 仅适用于承诺。
  • 如果你已经有一个你想要await的承诺,你不需要new Promise()开始,因为主要用例new Promise 的目的是将 使用 promises 的东西转换成可以使用的东西。