获得第一个履行承诺

时间:2016-10-09 04:54:38

标签: javascript node.js promise es6-promise

如果我有两个承诺A和B,其中只有一个会成功,我怎样才能获得成功完成的任何承诺?我正在寻找类似于Promise.race的东西,但它只会返回满足的第一个承诺。我使用了ES6的承诺。

5 个答案:

答案 0 :(得分:12)

反转承诺的极性,然后你可以使用Promise.all,因为它拒绝了第一个被拒绝的承诺,它在反转后对应于第一个履行的承诺:

const invert  = p  => new Promise((res, rej) => p.then(rej, res));
const firstOf = ps => invert(Promise.all(ps.map(invert)));

// Utility routines used only in testing.
const wait    = ms => new Promise(res => setTimeout(() => res(ms), ms));
const fail    = f  => Promise.reject(f);
const log     = p  => p.then(v => console.log("pass", v), v => console.log("fail", v));

// Test.
log(firstOf([wait(1000), wait(500) ]));
log(firstOf([wait(1000), fail("f1")]));
log(firstOf([fail("f1"), fail("f2")]));

这将返回第一个履行承诺的值,或者如果全部拒绝,则返回一系列拒绝原因。

答案 1 :(得分:3)

如果你想要第一个成功解决的承诺并且你想忽略之前的任何拒绝,那么你可以使用这样的东西:

// returns the result from the first promise that resolves
// or rejects if all the promises reject - then return array of rejected errors
function firstPromiseResolve(array) {
    return new Promise(function(resolve, reject) {
        if (!array || !array.length) {
            return reject(new Error("array passed to firstPromiseResolve() cannot be empty"));
        }
        var errors = new Array(array.length);
        var errorCntr = 0;
        array.forEach(function (p, index) {
            // when a promise resolves
            Promise.resolve(p).then(function(val) {
                // only first one to call resolve will actually do anything
                resolve(val);
            }, function(err) {
                errors[index] = err;
                ++errorCntr;
                // if all promises have rejected, then reject
                if (errorCntr === array.length) {
                    reject(errors);
                }
            });
        });
    });
}

我不知道如何使用Promise.race()这样做,因为它只是报告完成的第一个承诺,如果第一个承诺拒绝,它将报告拒绝。所以,你在问题中所做的并不是要报告解决的第一个承诺(即使在它之前完成了一些拒绝)。

仅供参考,the Bluebird promise library同时拥有Promise.some()Promise.any(),可以为您处理此案例。

答案 2 :(得分:2)

ES2021 / ES12-Promise.any

Promise.any-第一个已达成的承诺胜利。

const promiseA = Promise.reject();
const promiseB = new Promise((resolve) => setTimeout(resolve, 100, 'succeed'));

const promises = [promiseA, promiseB];


Promise.race(promises).then((value) => console.log(value)); // rejected promise

Promise.any(promises).then((value) => console.log(value)); // "succeed"

请注意,any正在忽略第一个被拒绝的承诺-promiseA,因为promiseB正在解决

如果所有给定的承诺都被拒绝,则返回的承诺也将被拒绝。


这是finished proposal,计划于ES2021(预计于2021年6月发布)

答案 3 :(得分:1)

我也有同样的问题,并给出了答案。您可以自己尝试这些问题,学到很多东西!

  1. 可接受的答案非常优雅,但是使用Promise.all可以使学习Promises的人感到开心;也很难跟随imo。
  2. jfriend00的答案与我的相似,但其逻辑超出了Promises基本原则,这在这里最重要。

我已经利用了公认的答案上那些漂亮的助手功能:

function firstPromise(promiseL, promiseR) {
    return new Promise((resolve, reject) => {
        promiseL.then(l => {
            resolve(l);
        }).catch(error => null);

        promiseR.then(r => {
            resolve(r);
        }).catch(error => null);


        promiseL.catch(errorL => {
            promiseR.catch(errorR => {
                reject(errorL + errorR);
            })
        })
    })
}

const wait = ms => new Promise(res => setTimeout(() => res(ms), ms));
const log = p => p.then(v => console.log("pass", v), v => console.log("fail", v));


log(firstPromise(wait(1000), wait(500)));
log(firstPromise(wait(1000), Promise.reject("Bar")));
log(firstPromise( Promise.reject("Foo"), wait(500)));
log(firstPromise( Promise.reject("Foo"), Promise.reject("Bar")));

答案 4 :(得分:0)

 //example 1
    var promise_A = new Promise(function(resolve, reject) {
        // выполнить что-то, возможно, асинхронно…
        setTimeout(function(){

            return  resolve(10);
            //return reject(new Error('ошибка'))
        },10000)
    });

    var promise_B = new Promise(function(resolve, reject) {
        // выполнить что-то, возможно, асинхронно…

        setTimeout(function(){
            return  resolve(100);
        },2000)
    });


/*
 //[100,10]
 Promise.all([
  promise_A,promise_B
 ]).then(function(results){
  console.log(results)
 });
*/

 //100
 Promise.race([
  promise_A,promise_B
 ]).then(function(results){
  console.log(results)
 });