为什么JavaScript的’Promise.all`在失败条件下没有运行所有承诺?

根据MDN

If any of the passed in promises rejects, the all Promise immediately rejects with the value of the promise that rejected, discarding all the other promises whether or not they have resolved.

ES6 spec似乎证实了这一点.

我的问题是:为什么Promise.all会丢弃承诺,如果他们中的任何一个拒绝,因为我希望它等待“所有”承诺解决,“丢弃”究竟是什么意思? (很难说“丢弃”对于飞行中的承诺与可能尚未运行的承诺意味着什么.)

我问,因为我经常遇到一些情况,我有一份承诺清单,并希望等待他们全部解决并得到可能已经发生的所有拒绝,Promise.all不满足.相反,我必须使用这样的黑客:

const promises = []; // Array of promises
const settle = promise => promise.then(result => ({ result }), reason => ({ reason }));
Promise.all(promises.map(settle))
  .then(/ * check "reason" property in each element for rejection */);

解决方法:

与promises关联的异步操作都已运行.如果其中一个承诺拒绝,那么Promise.all()根本不会等待所有这些承诺完成,它会在第一个承诺拒绝时拒绝.这就是它的设计工作方式.如果你需要不同的逻辑(就像你想要等待所有这些逻辑完成,无论它们是否满足),那么你就不能只使用Promise.all().

请记住,承诺不是异步操作本身. promise只是一个跟踪异步操作状态的对象.因此,当您将Promise数组传递给Promise.all()时,所有这些异步操作都已经启动并且已经在进行中.它们不会被停止或取消.

Why does Promise.all discard promises if any of them reject, since I would expect it to wait for “all” promises to settle.

它的工作方式与它的工作方式相同,因为它是如何设计的,当你不希望代码在有任何错误的情况下继续时,这是一个非常常见的用例.如果碰巧不是你的用例,那么你需要使用.settle()的一些实现,它具有你想要的行为(你似乎已经知道了).

我发现更有趣的问题是为什么规范和标准实现中没有.settle()选项,因为它也是一个相当常见的用例.幸运的是,正如您所发现的那样,创建自己的代码并不是很多.当我不需要实际的拒绝原因并且只想将一些指标值放入数组时,我经常使用这个相当简单的版本:

// settle all promises.  For rejeted promises, return a specific rejectVal that is
// distinguishable from your successful return values (often null or 0 or "" or {})
Promise.settleVal = function(rejectVal, promises) {
    return Promise.all(promises.map(function(p) {
        // make sure any values or foreign promises are wrapped in a promise
        return Promise.resolve(p).catch(function(err) {
            // instead of rejection, just return the rejectVal (often null or 0 or "" or {})
            return rejectVal;
        });
    }));
};

// sample usage:
Promise.settleVal(null, someArrayOfPromises).then(function(results) {
    results.forEach(function(r) {
        // log successful ones
        if (r !== null) {
           console.log(r);
        }
    });
});

what exactly does “discard” mean?

它只是意味着Promise.all()不再跟踪承诺.与它们相关联的异步操作始终保持正在执行的任何操作.事实上,如果这些承诺上有.then()处理程序,它们就会像通常那样被调用.在这里使用discard似乎是一个不幸的术语.除了Promise.all()之外没有其他任何事情可以停止关注它们.

仅供参考,如果我想要一个更强大的.settle()版本来跟踪所有结果并拒绝原因,那么我使用它:

// ES6 version of settle that returns an instanceof Error for promises that rejected
Promise.settle = function(promises) {
    return Promise.all(promises.map(function(p) {
        // make sure any values or foreign promises are wrapped in a promise
        return Promise.resolve(p).catch(function(err) {
            // make sure error is wrapped in Error object so we can reliably detect which promises rejected
            if (err instanceof Error) {
                return err;
            } else {
                var errObject = new Error();
                errObject.rejectErr = err;
                return errObject;
            }
        });
    }));
}

// usage
Promise.settle(someArrayOfPromises).then(function(results) {
    results.forEach(function(r) {
       if (r instanceof Error) {
           console.log("reject reason", r.rejectErr);
       } else {
           // fulfilled value
           console.log("fulfilled value:", r);
       }
    });
});

这解决了一系列结果.如果结果是instanceof Error,那么它被拒绝,否则它是一个满足的值.

相关文章

最后的控制台返回空数组.控制台在ids.map函数完成之前运行va...
我正在尝试将rxJava与我已经知道的内容联系起来,特别是来自J...
config.jsconstconfig={base_url_api:"https://douban....
我正在阅读MDN中的javascript,并且遇到了这个谈论承诺并且不...
config.jsconstconfig={base_url_api:"https://douban....
这是我的代码main.cpp:#include<string>#include<...