使用下面的代码,其中一个对象data
被初始化为一些值,然后由一些时间密集型函数处理,如数据库访问。如果函数成功,则成功的data
项的名称将打印到控制台。否则,将打印失败通知:
data = {first: 'someinfo', second: 'somemoreinfo', third: 'evenmoreinfo'};
for (var item in data) {
timeIntensiveFunction(item, data[item], function(err) {
if (!err) {
console.log(item + ' processed successfully');
} else {
console.log(item + ' failed');
}
});
}
假设该功能对所有三个数据项都成功,您会期望控制台显示此:
first processed successfully
second processed successfully
third processed successfully
相反,它会显示此,假设第一个数据库访问时间超过for
循环:
third processed successfully
third processed successfully
third processed successfully
这是因为控制台日志记录是在回调中完成的,在for
循环完成后合理地仅被称为,因为{{1需要很长时间。 调用第一个回调时,timeIntensiveFunction()
已经有了最后一个值item
。
你如何通过'当前'项的值进入回调?
答案 0 :(得分:0)
问题是因为它只使用最后一项调用回调。
您可以使用类似下面的函数绑定每个项目。
var printStatus = function(item){
return function(err) {
if (!err) {
console.log(item + ' processed successfully');
} else {
console.log(item + ' failed');
}
}
}
for (var item in data) {
timeIntensiveFunction(item, data[item], printStatus(item));
}
答案 1 :(得分:0)
这是javascript中带闭包的常见“问题”。解决它的一种方法是将函数调用包装在匿名函数中并重新扫描item
。像这样:
for (var item in data) {
(function(item){
timeIntensiveFunction(item, data[item], function(err) {
if (!err) {
console.log(item + ' processed successfully');
} else {
console.log(item + ' failed');
}
});
})(item);
}
答案 2 :(得分:0)
如果您正在寻找能够更轻松地处理异步任务的库,请查看caolan/async。
var async = require("async");
var data = [{id: "first"}, {id: "second"}, {id: "third"}];
function timeIntensiveFunction(item, done) {
// do something
console.log("time intensive task started:", item.id);
// err?
// if (err) return done(err);
done();
}
function processItem(item, done) {
timeIntensiveFunction(item, function(err) {
if (err) return done(err);
console.log("task complete:", item.id);
done();
});
}
async.map(data, processItem);
输出
time intensive task started: first
task complete: first
time intensive task started: second
task complete: second
time intensive task started: third
task complete: third
对于希望在没有库的情况下学习如何执行此操作的用户,您可以查看此答案的修订历史记录。