使用forEach时,避免回调多次调用

时间:2018-05-21 17:16:55

标签: node.js asynchronous promise

我有一个处理数据数组的函数(第一个参数),一旦处理完成,它只调用一次一个回调函数(第二个参数)。我使用forEach逐项处理数据,包括处理某些检查中的每个项目并将参数存储在数据库中。函数storeInDB()执行存储工作,并在存储项目时使用回调(第二个参数)。

代码的第一种方法如下:

function doWork(data, callback) {
    data.forEach(function (item) {
        // Do some check on item
        ...
        storeInDB(item, function(err) {
           // check error etc.
           ...
           callback();
        });
    });
}

然而,这是错误的,因为callback函数将被调用多次(与data数组中的元素一样多)。

我想知道如何重构我的代码以实现所需的行为,即一旦存储工作完成,只需要调用一次callback。我想async可以帮助完成这项任务,但我还没有找到合适的模式来组合async + forEach。

感谢任何帮助!

3 个答案:

答案 0 :(得分:1)

您可以使用async这样的库来执行此操作,但我建议尽可能使用promises。对于您的直接问题,您可以使用计数器来确定已完成的存储呼叫数量,并在总数完成时调用回调。

let counter = 0;
data.forEach(function (item) {
    // Do some check on item
    ...
    storeInDB(item, function(err) {
       // check error etc.
       counter++
       if (counter == data.length) {
         callback();
       }
    });
});

答案 1 :(得分:1)

如果storeInDB函数返回一个promise,您可以将所有异步函数推送到一个数组并使用 Promise.all 。在所有任务成功运行后,它将调用回调函数。

希望这会对你有所帮助。

function doWork(data, callback) {
  let arr = [];
  data.map(function(itm) {
    // Do some check on item
    ...
    arr.push(storeInDB(item));
  });
  Promise.all(arr)
    .then(function(res) {
      callback();
    });
}

答案 2 :(得分:1)

您还可以利用传递给函数的三个参数在每个数组方法上执行

function doWork(data, callback) {

    data.forEach(function (value,idx,arr) {
        // Do some check on item
        ...
        storeInDB(arr[idx], function(err) {
            // check error etc.
            ...
            if ( (idx + 1) === arr.length ) {
                callback();
            }
        });
    });
 }