将数据传递给node.js回调 - 异步问题

时间:2014-07-23 02:43:14

标签: javascript node.js asynchronous callback

使用下面的代码,其中一个对象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

你如何通过'当前'项的值进入回调?

3 个答案:

答案 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

对于希望在没有库的情况下学习如何执行此操作的用户,您可以查看此答案的修订历史记录。