我有一个处理数据数组的函数(第一个参数),一旦处理完成,它只调用一次一个回调函数(第二个参数)。我使用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。
感谢任何帮助!
答案 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();
}
});
});
}