How do you implement a “raceToSuccess” helper, given a list of promises?

后端 未结 7 1816
孤城傲影
孤城傲影 2020-12-02 23:37

I\'m puzzled by something in the ES6 Promise API. I can see a clear use case for submitting multiple async jobs concurrently, and \"resolving\" on the first success. This wo

7条回答
  •  情话喂你
    2020-12-03 00:00

    I'm using a function based on Promise.race() but with a twist: it ignores rejects, unless all given promises reject:

    // ignores any rejects except if all promises rejects
    Promise.firstResolve = function (promises) {
        return new Promise(function (fulfil, reject) {
            var rejectCount = 0;
            promises.forEach(function (promise) {
                promise.then(fulfil, () => {
                    rejectCount++;
                    if(rejectCount == promises.length) {
                        reject('All promises were rejected');
                    } 
                });
            });
        });
    };
    

    It's based on Rich Harris's Promise polyfill race method. I just made the looping promise reject conditional: it only rejects the main promise, if all given promises failed, otherwise it ignores rejects and resolves the first success.

    Usage:

    // fastest promise to end, but is a reject (gets ignored)
    var promise1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            reject("foo")
        }, 100);
    })
    
    // fastest promise to resolve (wins the race)
    var promise2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("bar")
        }, 200);
    })
    
    // Another, slower resolve (gets ignored)
    var promise3 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("baz")
        }, 300);
    })
    
    Promise.firstResolve([promise1, promise2, promise3])
        .then((res) => {
            console.log(res) // "bar"
        })
        .catch(err => {
            console.log(err) // "All promises were rejected" (if all promises were to fail)
        })
    

    The reason I use this instead of the promise inverting approach, is because in my opinion this is more readable.

    To please the question in the strictest way, below there is a version that resolves the first successful promise but doesn't do anything if all given promises fail:

    // ignores any and all rejects
    Promise.firstResolve = function (promises) {
        return new Promise(function (fulfil) {
            promises.forEach(function (promise) {
                promise.then(fulfil, () => {});
            });
        });
    };
    

    (usage same as above)

    Edit: This is in fact the same as @user663031's suggestion. Which I haven't realized until just now.

提交回复
热议问题