Home > Net >  await Promise.all(promises) never completes if an error is encountered
await Promise.all(promises) never completes if an error is encountered

Time:09-05

I thought await Promise.all(promises) would continue even if there was an error encountered, but I am finding this not to be the case. Am I doing something wrong or do I just not understand what await is supposed to do?

The code snippet below illustrates the problem. promiseSimulator will return the number passed unless it is 5, which will generate an error. The line of code after await Promise.all(promises) will execute only if I remove the code to generate the error. Otherwise, if an error is encountered, the await never completes. How can I get this to work correctly?

    async runTest() {
    const promises:Promise<number>[] = []; 
    for (let i = 0; i < 10; i  ) {
      const promise:Promise<number> = this.promiseSimulator(i); 
      promises.push(promise); 
      promise 
        .then( (response:number) => console.log('response: ', response)) 
        .catch( (error:any) => console.log('error', error) ); 
    }
    console.log('begin await all'); 
    await Promise.all(promises); 
    console.log('done await all');
  }

  private promiseSimulator(input:number):Promise<number> {
    return new Promise<number>(
      (resolve, reject) => {
        setTimeout( () => {
          if (input === 5) {
            reject(new Error("Found a 5")); 
          }
          else {
            resolve(input); 
          }
        }, 100)
      }
    );
  }

CodePudding user response:

Promise.all() will complete if every internal promise completes. However, the last console.log() will not run:

console.log('begin await all'); 
await Promise.all(promises); 
console.log('done await all');

This is because if any of the promises rejects, then the result of Promise.all() does as well, which means it gets turned into an exception in the async function. You can catch it though:

console.log('begin await all');
try { 
  await Promise.all(promises);
} finally {
  console.log('done await all');
}

Or you can use Promise.allSettled() instead of Promise.all().

CodePudding user response:

If you want Promise.all() to succeed even if there are errors within one of the promises that you pass to it, I would recommend wrapping each in an intermediate promise which resolves regardless of the outcome of the inner promise. This can be done easily with a .map() within the .all call.

async function runTest() {
  const promises = [];
  for (let i = 0; i < 10; i  ) {
    const promise = promiseSimulator(i);
    promises.push(promise);

  }
  console.log('begin await all');
  await Promise.all(promises.map(errorCatcher));
  console.log('done await all');
}

function errorCatcher(inPromise) {
  return new Promise(resolve => {
    inPromise
      .then(result => {
        console.log(result);
        resolve(result)
      })
      .catch(result => {
        console.log("ERRROR "   result)
        resolve("ERRROR "   result);
      });
  })
}


function promiseSimulator(input) {
  return new Promise(
    (resolve, reject) => {
      setTimeout(() => {
        if (input === 5) {
          reject(new Error("Found a 5"));
        } else {
          resolve(input);
        }
      }, 100)
    }
  );
}

runTest();

  • Related