0

Looking at previous answers, an appropriate way to handle errors inside a Promise.all is by using something like:

  Promise.all(
    promises.map(p => p.catch(error => null))
  )

In my code I want to pass an async func inside the mapping of the promise and be able to run a catch should that promise fail, without it killing the entire chain.

My code:

const handler = async (item) => {
   const result = await Promise()
   return result
}

const items = [1,2,3]

const results = await Promise.all(items.map(handler))

How would I be able to run the handler func inside the Promise.all while still catching for errors and keeping the chain alive?

Chris Ngo
  • 15,460
  • 3
  • 23
  • 46
  • Wait, am I tripping or are you trying to handle rejection of any Promise inside `Promise.all()`? Because `Promise.all()` rejects entirely as soon as any Promise fails. – Robo Robok May 19 '20 at 01:34
  • @RoboRobok correct me if I'm mistaken, but I believe there have been some enhancements made to support error-catching in Promise.all to preserve the active chain. https://stackoverflow.com/questions/43503872/promise-all-alternative-that-allows-failure – Chris Ngo May 19 '20 at 01:40
  • There has been an improvement in form of `Promise.allSettled()`. The older `Promise.all()` rejects whenever anything inside it rejects and doesn't even care about unfinished promises. – Robo Robok May 19 '20 at 01:44
  • @RoboRobok can confirm that the first solution using Promise.all provided at all, does in fact work for my use-case. – Chris Ngo May 19 '20 at 04:03
  • 1
    It works, because these Promises inside never reject. The rejection is muted by then(). That is done before these Promises go inside Promise.all(). – Robo Robok May 19 '20 at 09:07
  • @RoboRobok if they are muted by then(), would they still execute simultaneously, or do they now have a synchronous nature? – Chris Ngo May 19 '20 at 18:14
  • 1
    I meant by your catch(), which is an alias for then(undefined, calback) anyway. Promises never have synchronous nature. When you put a Promise with multiple then() and catch() to Promise.all(), the end of each chain is the final promise. But they still work asynchronously. The only thing with Promise.all() is that it knows when all of them are resolved or any of them rejects (without catching, that is). – Robo Robok May 19 '20 at 18:28
  • Thank you, great explanation! – Chris Ngo May 19 '20 at 18:29

1 Answers1

1

Write another function for the .map to do the same thing you're doing in the first code block: invoke handler and .catch if it throws:

const results = await Promise.all(
  items.map(
    item => handler(item).catch(error => null)
  )
);

Or, with Promise.allSettled:

const results = await Promise.allSettled(items.map(handler));

The above will result in an array of objects. To find the results that went through successfully, extract the value from the objects that have it:

const truthyResults = results
  .map(({ value }) => value)
  .filter(value => value !== undefined);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320