skip to Main Content

Let’s suppose I have 5 promises (A,B,C,D,E) that I want to fire in parallel. Then I need to wait for any of (A,B) AND any of (C,D) AND E before executing a code.
My actual approach was something like:

let promises_AB = new Array();
let promises_CD = new Array();
let promises_E = new Array();
promises_AB.push(promiseA());
promises_AB.push(promiseB());
promises_CD.push(promiseC());
promises_CD.push(promiseD());
promises_E.push(promiseE());

//Promises on top will execute in parallel

try{
  let res = await Promise.any(promises_AB);
  //Do code after getting AB
} catch (e){
  //error handler
}
try{
  let res = await Promise.any(promises_CD);
  //Do code after getting CD
} catch (e){
  //error handler
}
try{
  let res = await Promise.any(promises_E);
  //Do code after getting E
} catch (e){
  //error handler
}

//DO CODE HERE which executes after promises A,B,C,D,E

The problem here is that since promises CD can be faster than AB, since I await first for AB, if an error occurs in CD before AB returns I don’t have yet the try/catch for CD and I get a unhandled promise rejection.
The only (bad) solution I see is a big try/catch around all three awaits but I wanted to differentiate the error handler per promise group.

3

Answers


  1. You can "merge" the processing using Promise.all:

    const [resAB, resCD, resE] = await Promise.all([
      Promise.any(promises_AB),
      Promise.any(promises_CD),
      Promise.any(promises_E),
    ]);
    
    // Do after all
    
    Login or Signup to reply.
  2. Use Promise.all() to wait for each Promise.any() in parallel.

    let [result_AB, result_CD, result_E] = await Promise.all(
        Promise.any(promises_AB), 
        Promise.any(promises_CD), 
        Promise.any(promises_E)
    )
    
    Login or Signup to reply.
  3. You could use Promise.all() to group the promises:

    let promises_AB = Promise.any([promiseA(), promiseB()]);
    let promises_CD = Promise.any([promiseC(), promiseD()]);
    let promises_E = promiseE(); // No need for Promise.any since it's just one promise
    
    try {
      let [resAB, resCD, resE] = await Promise.all([promises_AB, promises_CD, promises_E]);
      // Do code after getting A or B, C or D, and E
    } catch (e) {
      // e is the rejection value of the first rejected promise.
    } 
    

    Alternatively, you could use Promise.allSettled() if you want to wait for all the promises to settle, regardless of whether they were fulfilled or rejected. This would allow you to differentiate the error handling per promise group and handle cases where some promises are rejected, and others are fulfilled:

    let promises_AB = Promise.any([promiseA(), promiseB()]);
    let promises_CD = Promise.any([promiseC(), promiseD()]);
    let promises_E = promiseE();
    
    let results = await Promise.allSettled([promises_AB, promises_CD, promises_E]);
    
    if (results[0].status === 'rejected') {
      // Handle error for promises_AB
    }
    if (results[1].status === 'rejected') {
      // Handle error for promises_CD
    }
    if (results[2].status === 'rejected') {
      // Handle error for promises_E
    }
    
    if (results[0].status === 'fulfilled' && results[1].status === 'fulfilled' &&
        results[2].status === 'fulfilled') {
      // Do code after getting A or B, C or D, and E
    }
    

    See recent relevant video Dangers of Promise.all() by t3dotgg@

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search