Get first fulfilled promise

徘徊边缘 提交于 2019-12-28 06:35:27

问题


If I have two promises A and B, only one of which will succeed, how can I get whichever one fulfills successfully? I'm looking for something similar to Promise.race, but which will return only the first promise that fulfills. I'm using promises from ES6.


回答1:


Invert the polarity of the promises, and then you can use Promise.all, because it rejects on the first rejected promise, which after inversion corresponds to the first fulfilled promise:

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")]));

This will return the value of the first fulfilled promise, or if all reject, an array of rejection reasons.




回答2:


If you want the first promise that resolves successfully and you want to ignore any rejections that come before that, then you can use something like this:

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

I don't see how you can use Promise.race() for this because it simply reports the first promise to finish and if that first promise rejects, it will report a rejection. So, it is not doing what you asked in your question which is to report the first promise that resolves (even if some rejections finished before it).

FYI, the Bluebird promise library has both Promise.some() and Promise.any() which can handle this case for you.




回答3:


I had the same question and gave it a go. You learn a lot by trying these problems yourself!

  1. The accepted answer is very elegant but uses Promise.all which takes the fun for someone learning Promises; also a bit hard to follow imo.
  2. jfriend00's answer is similar to mine but has that logic that goes beyond the Promises fundamentals which is most important here.

I have made use of those nice helper functions present on the accepted answer:

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:


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


来源:https://stackoverflow.com/questions/39940152/get-first-fulfilled-promise

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!