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

后端 未结 7 1787
孤城傲影
孤城傲影 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:06

    You can write this quite easily yourself.

    function raceToSuccess(promises) {
      return new Promise(
        resolve => 
          promises.forEach(
            promise => 
              promise.then(resolve)
          )
      );
    }
    

    This kicks off all the promises, and when any succeeds resolves the new promise with its value. Failed promises are ignored. Subsequent successful promises cause nothing to happen, since the new promise has already been resolved. Note that the resulting promise will never resolve or reject if none of the input promises resolve.

    Here is a modified version which returns a rejected promise if all of the input promises reject:

    function raceToSuccess(promises) {
      let numRejected = 0;
    
      return new Promise(
        (resolve, reject) => 
          promises.forEach(
            promise => 
              promise . 
                then(resolve) .
                catch(
                  () => {
                    if (++numRejected === promises.length) reject(); 
                  }
               )
           )
      );
    }
    

    I like @loganfsmyth's approach; you should probably upvote it for its conceptual clarity. Here's a variation of it:

    function invertPromise(promise) {
      return new Promise(
        (resolve, reject) => 
          promise.then(reject, resolve)
      );
    }
    
    function raceToSuccess(promises) {
      return invertPromise(
        Promise.all(
          promises.map(invertPromise)));
    }
    

    Another idea is to turn the failed promises into promises which neither resolve nor reject (in other words, are permanently pending), then use Promise.race:

    function pendingPromise()      { return new Promise(() => { }); }
    function killRejected(promise) { return promise.catch(pendingPromise); }
    
    function raceToSuccess(promises) {
      return Promise.race(promises.map(killRejected));
    }
    

    You may or not like the behavior of this. The returned promise will never fulfill or reject if none of the input promises fulfill. It's also possible that the permanently pending promises will not get GC'd, or some engines might eventually complain about them.

    0 讨论(0)
提交回复
热议问题