admin管理员组

文章数量:1420197

As per MDN,

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.

Here is a code-snippet which doesn't catch the error as I expected it to as per above definition :-

const promise1 = Promise.resolve(3);
const promise2 = () => {throw new Error('random error')};
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2(), promise3]).then((values) => {
  console.log(values);
}).catch(e=>console.log('Error caught',e));

As per MDN,

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.

Here is a code-snippet which doesn't catch the error as I expected it to as per above definition :-

const promise1 = Promise.resolve(3);
const promise2 = () => {throw new Error('random error')};
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2(), promise3]).then((values) => {
  console.log(values);
}).catch(e=>console.log('Error caught',e));

I know if I convert the promise2() to return a Promise which rejects then it will work. But what about the non-promises line ? Is it incorrect or am I missing something ?

Update - I got the answer for this behavior. Just curious about what could be possible scenarios for non-promises throwing an error as per the definition ?

Share Improve this question edited Jul 5, 2021 at 8:36 Lakshya Thakur asked Jul 5, 2021 at 8:15 Lakshya ThakurLakshya Thakur 8,3261 gold badge14 silver badges42 bronze badges 2
  • It's like doing: const input = [promise1, promise2(), promise3]; Promise.all(input) Nothing to do with Promise.all – adiga Commented Jul 5, 2021 at 8:19
  • 3 If you wanted it to behave like you're imaging, just pop an async in there: const proimse2 = async () => ... – TKoL Commented Jul 5, 2021 at 8:21
Add a ment  | 

2 Answers 2

Reset to default 7

Because the error is thrown before you call Promise.all. It's impossible for Promise.all to convert that to rejection for you.

You're calling promise2 when building the array, which happens before you pass that array to Promise.all.

Your code here:

Promise.all([promise1, promise2(), promise3])/*...*/

...is equivalent to the following (other than the variables):

const x0 = promise1;
const x1 = promise2(); // <==== Error is thrown here
const x2 = promise3;
const array = [x0, x1, x2];
Promise.all(array)/*...*/

To make it work as you want, you have several options:

You could make it an async function, as TKoL pointed out in a ment:

const promise1 = Promise.resolve(3);
const promise2 = async () => {throw new Error('random error')};
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2(), promise3]).then((values) => {
  console.log(values);
}).catch(e=>console.log('Error caught',e));

That works because async functions always return promises (even if you don't use await) and an error in an async function rejects the promise it returns.

You could make promise2 a thenable so it doesn't throw until then is called, then Promise.all would convert that to rejection for you:

const promise1 = Promise.resolve(3);
const promise2 = {
    then() {
        throw new Error('random error');
    }
};
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

// Note no () on promise2 below
Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
}).catch(e=>console.log('Error caught',e));

JS first tries to get the arguments correct - then passes the arguments to the function which is called. In your scenario, an error is thrown even before the Promise.all is called.

To better understand the situation and realize that the Promise interface has nothing to do with your case, see the attached snippet. The PromiseAllTest function is called with the 3 arguments included in the quesion. But you can see the function is not even called. The error is thrown before it.

const promise1 = Promise.resolve(3);
const promise2 = () => {throw new Error('random error')};
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});


try{
  console.log('Preparing to call Promise Test');
  PromiseAllTest([promise1, promise2(), promise3]);  
  console.log('Promise Test is called successfully');
}
catch(e) {
  console.log('Promise Test is not even called')
}

function PromiseAllTest(promiseArray) {
  console.log('Start Processing');
  console.log(promiseArray);
  console.og('End Processing');
}

本文标签: javascriptWhy Promiseall doesn39t reject when a nonpromise throws an errorStack Overflow