为什么JavaScript的`Promise.all`在失败情况下不能运行所有的Promise? [英] Why does JavaScript's `Promise.all` not run all promises in failure conditions?

查看:667
本文介绍了为什么JavaScript的`Promise.all`在失败情况下不能运行所有的Promise?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据 MDN


如果任何传入的诺言被拒绝,则所有Promise都会立即以被拒绝的诺言的价值来拒绝,并丢弃所有其他诺言

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规范似乎可以证实这一点。

The ES6 spec seems to confirm this.

我的问题是:为什么 Promise.all 如果任何一个都拒绝,则放弃承诺,因为我希望它等待所有承诺的达成,而放弃的确切含义是什么意思? (很难说放弃对于飞行中的承诺和尚未兑现的承诺意味着什么。)

My question is: Why does Promise.all discard promises if any of them reject, since I would expect it to wait for "all" promises to settle, and what exactly does "discard" mean? (It's hard to tell what "discard" means for in-flight promises vs. promises that may not have run yet.)

我问是因为我经常遇到以下情况:我有一个承诺清单,想等它们 all 完成,并得到可能发生的 all 拒绝,这是 Promise.all 不适合。相反,我必须使用这样的黑客:

I ask because I frequently run into situations where I have a list of promises and want to wait for them all to settle and get all rejections that may have occurred, which Promise.all doesn't cater to. Instead, I have to use a hack like this:

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 */);


推荐答案

与promise相关的异步操作都可以运行。如果其中一个承诺被拒绝,则 Promise.all()根本不等待所有承诺完成,而是在第一个承诺被拒绝时拒绝。这就是它设计工作的方式。如果您需要不同的逻辑(例如您想等待所有逻辑完成,无论它们是否实现),那么您就不能仅使用 Promise.all()

The asynchronous operations associated with the promises are all run. If one of those promises rejects, then Promise.all() simply does not wait for all of them to complete, it rejects when the first promise rejects. That is just how it was designed to work. If you need different logic (like you want to wait for all of them to be done, no matter whether they fulfill or reject), then you can't use just Promise.all().

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

Remember, a promise is not the async operation itself. A promise is just an object that keeps track of the state of the async operation. So, when you pass an array of promises to Promise.all(), all those async operations have already been started and are all in-flight already. They won't be stopped or cancelled.


为什么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()的某些实现,该实现具有您想要的行为(您似乎已经知道)。

It works the way it does because that's how it was designed and that is a very common use case when you don't want your code to continue if there was any sort of error. If it happens to not be your use case, then you need to use some implementation of .settle() which has the behavior you want (which you seem to already know).

我发现更有趣的问题是,为什么规范中没有 .settle()选项,并且标准实现,因为它也是一个相当普遍的用例。幸运的是,您已经发现,编写自己的代码并不多。当我不需要实际的拒绝原因而只希望将一些指标值放入数组中时,我经常使用这个相当简单的版本:

What I find the more interesting question is why is there not a .settle() option in the specification and standard implementation since it is also a fairly common use case. Fortunately, as you have found, it is not a lot of code to make your own. When I don't need the actual reject reason and just want some indicator value to be placed into the array, I often use this fairly simple to use version:

// 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()处理程序,则它们将像通常那样被调用。 放弃似乎是一个不幸的词。除了 Promise.all()停止关注之外,什么都没有发生。

It just means that the promises are no longer tracked by Promise.all(). The async operations they are associated with keep right on doing whatever they were going to do. And, in fact if those promises have .then() handlers on them, they will be called just as they normally would. discard does seem like an unfortunate term to use here. Nothing happens other than Promise.all() stops paying attention to them.

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

FYI, if I want a more robust version of .settle() that keeps track of all results and reject reasons, then I use this:

// 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,则表示该结果被拒绝,否则为已实现的值。

This resolves to an array of results. If a result is instanceof Error, then it was a rejected, otherwise it's a fulfilled value.

这篇关于为什么JavaScript的`Promise.all`在失败情况下不能运行所有的Promise?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆