4

I'm writing Javascript which needs these events to happen in this order:

  1. Fire off several API calls simultaneously
  2. Once all calls have completed and responses have returned, execute a line of code

Sounds simple but the tricky part is that I can't use Promises.all() because I still want that line of code to execute after all promises have been fulfilled, successful or not. Unless I misunderstand Promises.all(), one failing would cause the line of code to not execute in then() and execute too soon in error().

I very well might be missing something obvious but the only other way I can see would be to chain the API call promises together but that would result in not firing them all at once. So basically I think I need a version of Promises.all() that isn't "fail-fast".

What's the proper way to do this?

  • 1
    Promise.all() is to chain multiple promises one after another if they have a dependency. Accordingly if one fails it won't try the others at all and will return to your catch(). If you have tolerance on reject cases (errors) then you should manually chain your promises with thens and catches and take care of the rejected operations through their catch() and continue with the next promise from that catch(). – Redu Apr 28 '16 at 19:05
  • 1
    Not sure it's accurate to say that it won't "try" the others: they've all started running already by the time they're passed to Promise.all. So whatever behavior they have as well as any .then/catch() operations chained onto each one individually will still run. – Dtipson Apr 28 '16 at 20:44

2 Answers2

4

To do it strictly using ES6 promises, you will need to wrap each promise in another wrapper promise, which gets resolved when the wrapped promise is fulfilled or rejected.

You can do that like this:

Promise.all( 
  promises.map( promise => Promise.resolve( promise ).catch( _=>_ ) )
).then ( function ( ) {
    // All promises finished
} );

This assumes that promises is an array of promises and/or values.

Paul
  • 139,544
  • 27
  • 275
  • 264
  • Avoid the [`Promise` constructor antipattern](http://stackoverflow.com/q/23803743/1048572)! – Bergi Apr 28 '16 at 21:06
  • @Bergi I don't think it's an anti-pattern when it makes things more readable, but I updated it to avoid using the Promise constructor. – Paul Apr 28 '16 at 21:15
  • Except that it didn't, really :-) Btw, you can simplify even more: `.then(null, _=>_)` or `.catch(_=>_)` – Bergi Apr 28 '16 at 21:24
  • Thank you both Bergi and Paulpro (and Dtipson), I am new to promises and still trying to understand the answers given here, I will post back when I have tried my implementation! Sorry for the duplicate question, I could not find that thread when I originally searched for an answer! – Shannon Fluellen Apr 28 '16 at 21:36
  • I was able to use your answer and it seems to have done exactly what I needed, thank you again Paulpro! – Shannon Fluellen Apr 29 '16 at 19:18
1

There's probably a slicker way than this, and even a better written version of this particular approach, but instead of using Promise.all, you could just chain behavior to each promise (for both then and catch, so it doesn't matter) that updates a value in a master Promise.

const allPromises = arrayOfPromises => Promise((resolve,reject)=> {
  const ln = arrayOfPromises.length,
        done = 0;

  const allDone => _ => {
    if(++done===ln){ resolve(); }
  }
  arrayOfPromises.map(p=>p.then(allDone).catch(allDone));
});
Dtipson
  • 1,564
  • 16
  • 21