Ozan Mudul
Ozan Mudul

Reputation: 1010

Promises with ES6 destructuring fails when one of the promises don't succeed

There are a tons of topics about it but I couldn't find this case. Let me explain:

const [call1, call2, call3] = await Promise.all([promise1, promise2, promise3]);

If they succeed it should return allright, yes? But what if it fails? It throws me this: Unhandled Rejection (TypeError): (intermediate value) is not iterable

I could make it const calls = await.Promise.all(promises) then use it like calls[0] but is it possible any other way?

Upvotes: 1

Views: 1114

Answers (3)

Terry Lennox
Terry Lennox

Reputation: 30715

You could have a look at Promise.allSettled(), this returns a promise that resolves after all of the given promises have either fulfilled or rejected, with an array of objects that each describes the outcome of each promise.

So even if any of the promises reject, allSettled will resolve and will give you details of each promise outcome.

Browser compatibility is here: allSettled compatibility

async function testAllSettled() {
    const promises = [1,2,3].map(n => new Promise((res,rej) => setTimeout(n % 2 ? res: rej, 100, n)));
    let result = await Promise.allSettled(promises);
    console.log('Promise.allSettled result:', result);
}

testAllSettled()
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Ergis
Ergis

Reputation: 1229

You have to understand how Promise.all works.

From the docs:
The Promise.all() method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises. This returned promise will resolve when all of the input's promises have resolved, or if the input iterable contains no promises. It rejects immediately upon any of the input promises rejecting or non-promises throwing an error, and will reject with this first rejection message / error.

Example:

const promise1 = Promise.resolve(1)
const promise2 = Promise.reject('dummy error')
const promise3 = Promise.resolve(3)

const promises = [promise1, promise2, promise3] 

Promise.all(promises)
  .then(values => ...)
  .catch(err => console.log(err))

Output: 'dummy error'

Instead, you might consider Promise.allSettled.

From the docs:
The Promise.allSettled() method returns a promise that resolves after all of the given promises have either fulfilled or rejected, with an array of objects that each describes the outcome of each promise.

The same example, but with Promise.allSettled:

Promise.allSettled(promises)  
.then(values => console.log(values))  

Output: [
{ status: "fulfilled", value: 1 },
{ status: "rejected", value: 'dummy error' },
{ { status: "fulfilled", value: 3 }
]

Upvotes: 2

Joseph
Joseph

Reputation: 119877

Awaiting a promise that will reject will cause the function to throw an exception. You handle that with a try-catch.

try {
  const [call1, call2, call3] = await Promise.all([promise1, promise2, promise3]);
} catch (error) {
  // Assuming the rejection value is an Error instance.
  const message = error.message
}

Upvotes: 3

Related Questions