使用 forEach 时避免回调多次调用
Posted
技术标签:
【中文标题】使用 forEach 时避免回调多次调用【英文标题】:Avoid callback multi-invocation when forEach is used 【发布时间】:2018-10-31 09:31:48 【问题描述】:我有一个处理数据数组的函数(第一个参数),一旦处理完成,它只调用一次回调函数(第二个参数)。我正在使用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。
感谢任何帮助!
【问题讨论】:
【参考方案1】:您可以使用诸如 async
之类的库来执行此操作,尽管我建议尽可能使用 Promise。对于您当前的问题,您可以使用计数器来确定已完成多少存储调用,并在总数完成时调用回调。
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();
);
);
【讨论】:
【参考方案2】:你也可以利用传递给函数的三个参数对每个数组方法执行
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();
);
);
【讨论】:
【参考方案3】:如果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();
);
【讨论】:
在这种情况下(以及任何其他情况,顺便说一句)你不应该使用forEach
,而是使用map
storeInDB有回调时,不代表返回promise? @Bergi
如果它需要一个回调,那通常意味着它不返回一个promise。
嗯,好的提示,谢谢。以上是关于使用 forEach 时避免回调多次调用的主要内容,如果未能解决你的问题,请参考以下文章