1

I need to iterate an array in javascript with some values that will be used to call an asynchronous function that returns a promise. I can´t continue the next code section without all promises were completed.

In the following example, the function "processInvoices" has to resolve a promise until all promises inside were completed (assume that "confirmInvoice" is an asynchronous function that has different response times):

processInvoices(invoices)
{
  return new promise((resolve,reject)=>
    {
        invoices.forEach(number=> 
            {
            
                confirmInvoice(number)
                    .then(result=>{
                              if (!result)
                                {reject('Error confirming the invoice');}
                    });
            });
        resolve(true);  // Resolving here doesn´t mean that all promises were completed!

    });
}

init()  // triggered at load..
{
    let invoices = [2,4,8,16,31];
    processInvoices(invoices)
        .then(result=>
            { 
                if (result) // It´s probable that the following message isn´t accurate:
                    console.log('All invoices were processed');
            }).catch(reason=>{console.error(reason)});

}

With the code above, I can´t be sure that the "console.log (or any routine)" will be executed right away after all promises were completed.

UPDATE Promise.all(iterable) solves the problem :

processInvoices(invoices)
{
  return new promise((resolve,reject)=>
    {
        var promisesArray = []; // store all promises here
        invoices.forEach(number=> 
            {
            
                promisesArray.push(confirmInvoice(number));
                    
            });
       Promise.all(promisesArray).then (results=>{
        // validate all results and reject if necessary...
        if (validateResults(results)) {
        // if all ok
            resolve('All invoices were processed successfully');
          }
        else {
          reject('Error processing one or more invoices'); // just for demo purposes
         }
        });                 

    });
}

init()  // triggered at load..
{
    let invoices = [2,4,8,16,31];
    processInvoices(invoices)
        .then(result=>
            {                   
            console.log(result);
            }).catch(reason=>{console.error(reason)});

}
3
  • Why are you passing invoices to processInvoices when processInvoices doesn't seem to use invoices anywhere? Did you mean to use invoices.map rather than parameters.map? Commented Oct 2, 2018 at 22:37
  • I fixed the example, its correct, is invoices the array to iterate Commented Oct 2, 2018 at 22:43
  • can we also assume that "confirmInvoice" is an asynchronous function that returns a Promise? It will need to Commented Oct 2, 2018 at 22:50

1 Answer 1

1

forEach runs synchronously. If you want to wait for all Promises to resolve before the full processInvoices resolves, you should use Promise.all instead; map each invoice number to a Promise and call Promise.all on the resulting array of Promises. Also, your

if (!result) {resolve(false);}

sounds like it's an attempt to handle an error, in case there is no result - in this case, you should reject the Promise instead of calling resolve. Ideally, the failed confirmInvoice call would result in a rejected Promise, but if that's not something you can fix, throw an error if result is falsey so you can handle it in a catch in init. For example:

function processInvoices(invoices) {
  return Promise.all(
    invoices.map(number => (
      confirmInvoice(number)
        .then(result => {
          // This will result in the `Promise.all` rejecting:
          if (!result) throw new Error('Failed to confirm invoice ' + number);
        })
    ))
  );
}
function init() {
  const invoices = [2, 4, 8, 16, 31];
  processInvoices(invoices)
    .then(result => {
        console.log('All invoices were processed');
    })
    .catch((err) => {
      console.log('err: ' + err);
    });
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your prompt response! I wrote this small example in order to explain the situation. I hope your answer helps other developers also :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.