【问题标题】:What happens to rejected promises inside Promise.race?Promise.race 中被拒绝的 Promise 会发生什么?
【发布时间】:2022-01-20 23:14:48
【问题描述】:

通常,当 JavaScript 中的 Promise 未经处理而拒绝时,我们会收到 unhandled promise rejection 错误。

但是,Promise.race 逻辑忽略的所有被拒绝的 Promise 会发生什么?为什么他们不抛出同样的错误?

考虑以下测试:

const normal = new Promise((resolve, reject) => {
    setTimeout(() => resolve(123), 100);
});

const err = new Promise((resolve, reject) => {
    setTimeout(() => reject('ops'), 500);
});

const test = Promise.race([normal, err]);

test.then(data => {
    console.log(data);
});

上面的测试只输出123,但我们的err promise 没有unhandled promise rejection 错误。

我试图了解所有那些被拒绝的承诺会发生什么,因此提出了这个问题。

我们最终可能会得到一堆松散的 Promise,它们会继续在后台运行,没有任何错误处理,也不会报告任何关于未处理的 Promise 拒绝的报告。这似乎有点危险。


举个例子。我试图为异步迭代实现combine 逻辑(类似于this),这需要使用Promise.race,同时跟踪传递给它的任何参数的拒绝,因为combine 函数需要然后拒绝下一个请求。

【问题讨论】:

  • 当你使用Promise.race 时,你告诉系统你只关心第一个被拒绝或解决的承诺,第二个被忽略。有关详细信息,请参阅文档。
  • "我试图了解所有那些被拒绝的承诺会发生什么,因此问题。" 没有任何反应。使用race,您只关心第一个完成的承诺,而不关心其余的。所以,被拒绝也没关系。实现它并不重要。
  • @fredrik 被Promise.race 忽略的承诺继续执行,并可能导致拒绝。我没有看到文档说像other rejected promises are just swallowed 这样的东西。您实际上最终会得到一堆松散的 Promise,这些 Promise 会继续在后台运行,并且没有任何错误处理。这似乎不对。
  • @vitaly-t 承诺没有“运行”。可以解决 Promise 的任务仍在运行,是的,但您无能为力,因为没有取消机制。
  • @Kaiido catch 从未在内部调用。总是.then() 有两个参数。

标签: javascript node.js promise


【解决方案1】:

来自MDN

Promise.race() 方法返回一个 Promise,一旦可迭代对象中的一个 Promise 满足或拒绝,该 Promise 就会满足或拒绝,并带有来自该 Promise 的值或原因。

您的代码实现了,因为更快的 Promise 调用了resolve。交换它们,它会拒绝。

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(reject, 100, 'two');
});

Promise.race([promise1, promise2]).then((value) => {
  console.log(value);
}).catch((value) => {
  console.log('error ', value);
});

【讨论】:

  • 这不是我问的。我询问了Promise.race 忽略的被拒绝的承诺会发生什么。
  • @vitaly-t — 好吧。什么都没有。
  • 存在关键字:忽略。他们按照正常方式解决或拒绝。任何监听它都会触发。 Promise.race 不会,因为它忽略了它们。
  • 我想我在这里问这个可以概括为here goes nothing
【解决方案2】:

通常,当 JavaScript 中的 Promise 未经处理而拒绝时,我们会得到 unhandled promise rejection 错误。

是的,当一个从未得到.then() 调用以安装处理程序的承诺被拒绝时,就会发生这种情况,即一个链的最终承诺。

(请注意,.catch(onRejected) 内部委托给.then(undefined, onRejected),因此承诺被标记为处理相同。)

但是,Promise.race 逻辑忽略的所有被拒绝的 Promise 会发生什么?为什么他们不抛出同样的错误?

Promise.race 确实在其参数中的所有承诺上调用 .then(),将它们标记为已处理:

Promise.race = function(thenables) {
    return new Promise((resolve, reject) => {
        for (const thenable of thenables) {
            Promise.resolve(thenable).then(resolve, reject);
        }
    });
};

请注意,当外部承诺已经解决时,它不会重新抛出错误,它只是被忽略了。这是设计使然:使用Promise.race 时,您声明您只对第一个结果感兴趣,其他所有内容都可以丢弃。从没有赢得比赛的承诺中导致未处理的承诺拒绝让您的应用程序崩溃将是相当具有破坏性的。

【讨论】:

  • 在我的示例中,如果我们附加处理程序:err.then().catch(),我们将看到.then 从未被调用,但.catch 被调用。所以我不知道Promise.race 调用then,它看起来不是那样的。
  • @vitaly-t 哪个例子?不,不要使用p.then(onFulfilled).catch(onRejected)use p.then(onFulfilled, onRejected) instead 附加处理程序。我给出的Promise.race 的实现是规范文本的相当直译。
  • 我在问题中提供的示例,它承诺err 会出错。我将thencatch 附加到它上面,并且只调用了catch,这是我所期望的。我的问题源于这样一个事实,即使它确实拒绝了,如果我根本不添加 catch ,什么也不会发生。
  • @vitaly-t 问题中的代码sn-p既没有err.then(…)也没有err.catch(…),只有Promise.race([…, err]),内部有err.then(…, …)。我错过了什么吗?
  • 您的回答听起来好像拥有.then(cb) 足以防止触发 unhandledrejection 事件,但事实并非如此,您也需要通过捕手。
猜你喜欢
  • 2019-11-22
  • 2018-05-15
  • 2017-01-04
  • 1970-01-01
  • 2018-08-17
  • 2021-08-08
  • 1970-01-01
  • 1970-01-01
  • 2016-12-03
相关资源
最近更新 更多