0

I had a few promises that do the same sort of thing, I was hoping to add a catch statement programatically to them and then run Promise.all on them. I had a few ideas for achieving this but it keeps blowing up in my face.

let promises = [
  Promise.reject('derp'), // Naïve test
  new Promise((resolve, reject) => { // Assumed this ran out of main loop
    reject('whayyy')
  }),
  new Promise((resolve, reject) => { // really assumed this ran out of main loop
    process.nextTick(() => reject('nooooon'))
  })
]

//fails
for(let promise of promises){
  promise.catch((err) => { return 'fixed programatically'} )
}
Promise.all(promises).then((things) => {
  console.log("Expect to make it here with no problems")
  console.log(things) 
})

I keep getting this for all three promises:

(node:25148) UnhandledPromiseRejectionWarning: derp|whayy|nooooon
(node:25148) UnhandledPromiseRejectionWarning: Unhandled promise rejection. 
This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)

Does anyone know how to properly do this?

Edit: I'm not sure why, I re-ran the original code and no longer get any errors. :(

unflores
  • 1,764
  • 2
  • 15
  • 35
  • 1
    Add a .catch on to your promise.all. pretty sure it will call it when one of them is rejected and not wait for the others. – Nathan Dec 09 '18 at 18:54

2 Answers2

3

You will need to replace each Promise in the array with the new Promise that is the result of calling catch. Otherwise you still just have the original (rejected) promise in the array, and then Promise.all ends up rejecting again and since you have no catch on that, you get an unhandled promise rejection error.

The best way to replace the promises in the array is probably to just use Array#map on the whole array:

promises = promises.map( promise => 
  promise.catch((err) => { return 'fixed programatically'} )
);

Full code (using setTimeout so it can run in a browser):

let promises = [
  Promise.reject('derp'), // Naïve test
  new Promise((resolve, reject) => { // Assumed this ran out of main loop
    reject('whayyy')
  }),
  new Promise((resolve, reject) => { // really assumed this ran out of main loop
    setTimeout(() => reject('nooooon'),0)
  }),
  Promise.resolve( 'success case, doesn\'t need fixing' ),
]

promises = promises.map( promise => 
  promise.catch((err) => { return 'fixed programatically'} )
);

Promise.all(promises).then((things) => {
  console.log("Expect to make it here with no problems")
  console.log(things) 
})
Paul
  • 139,544
  • 27
  • 275
  • 264
-1

Promise.all will fail altogether as soon as one of the promises in the arrays fail.

To get around this use the map function.

promises.map(promise => {
      return new Promise((resolve, reject) => {
        promise.then(resolve).catch(resolve);
      });
  });

So what we are doing in the above, is returning a new promise and always resolving it. Then pass that off to Promise.all

  • There is no need to use a Promise constructor there, and that is an anti-pattern. Your code is functionally equivalent to `promises.map(promise => promise.catch(x => x));`. Which doesn't do anything on its own either without reassigning the result to the `promises` variable. – Paul Dec 09 '18 at 19:10
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Dec 09 '18 at 21:10