简体   繁体   English

如何在 javascript 中迭代数组,在循环块内使用承诺并等待所有承诺完成以继续

[英]How to iterate an array in javascript, with promises inside the loop block and wait for all promises to be completed to continue

I need to iterate an array in javascript with some values that will be used to call an asynchronous function that returns a promise.我需要在 javascript 中迭代一个数组,其中一些值将用于调用返回承诺的异步函数。 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”必须解析一个promise,直到里面的所有promise完成(假设“confirmInvoice”是一个具有不同响应时间的异步函数):

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.使用上面的代码,我不能确定“console.log(或任何例程)”会在所有承诺完成后立即执行。

UPDATE Promise.all(iterable) solves the problem : UPDATE Promise.all(iterable) 解决了这个问题:

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)});

}

forEach runs synchronously . forEach同步运行。 If you want to wait for all Promises to resolve before the full processInvoices resolves, you should use Promise.all instead;如果你想在整个processInvoices解决之前等待所有 Promises 解决,你应该使用Promise.all代替; map each invoice number to a Promise and call Promise.all on the resulting array of Promises. map每个发票编号map到一个Promise并在生成的Promise数组上调用Promise.all 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 .听起来像是在尝试处理错误,以防万一没有结果 - 在这种情况下,您应该拒绝Promise而不是调用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 .理想情况下,失败的confirmInvoice调用将导致被拒绝的Promise ,但如果这不是您可以解决的问题,则在result为假时抛出错误,以便您可以在initcatch中处理它。 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);
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM