如何确定回调中的当前迭代次数(nodejs)

时间:2015-04-11 13:26:27

标签: javascript node.js

这是nodejs的代码。如果我记录变量的值" i"在response.on(" end")回调中,然后打印数字" 2"三次。我不明白为什么。

var http = require('http'),
        urls = [],
        requestsDone  = 0,
        result = [];

    for (var i in process.argv) {
        if (i > 1) {
            urls.push(process.argv[i]);
        }
    }

    for (var i in urls) {

        var nextUrl = urls[i];
        http.get(nextUrl, function(response){
            var allData = '';
            response.on("data", function(data){
                allData += data;
            });

            response.on("end", function(){
                console.log(i);
                result[requestsDone] = allData;
                requestsDone +=1;
                if (requestsDone == 3) {
                    console.log(result.join('\n'));
                }
            });
        });
    }

2 个答案:

答案 0 :(得分:1)

使用forEach(代替for (var i in urls)),这会创建一个新范围:

urls.forEach(function(nextUrl, i) {
  http.get(nextUrl, function(response) {
    ...
  });
});

答案 1 :(得分:0)

答案是因为http.get调用是异步的。

迭代for循环眨眼间从0转到urls.length,因为异步代码不会阻止它。另一方面,在迭代器从end迭代到0之后很久就会调用在事件urls.length回调中执行的代码,因此对console.log(i)的任何调用都将打印出来最终值,因为它在执行日志语句之前就达到了该值。

robertkelp 的解决方案是明智的,创建一个新的闭包(范围)是这里的方法。

这是一个简单的例子来展示你所看到的:

var array = [0,1,2,3,4,5,6,7,8,9];
for(i in array) {
    setTimeout(function() { //simulating the async nature of the http.get call
        console.log(array[i], i);
    }, 1000); 
}

这将打印9 9 10次,这就是你所看到的。

创建范围并传递i将确保捕获i的值,这是最简单的方法:

var array = [0,1,2,3,4,5,6,7,8,9];

function log(i) {
    setTimeout(function() {
        console.log(array[i], i);
    }, 1000); 
}

for(i in array) {
    log(i); //creating a new scope and capturing the value of i
}

和更成熟的方法(使用与 robertkelp 相同的forEach迭代器建议)

var array = [0,1,2,3,4,5,6,7,8,9];

array.forEach(function(number, i) { //forEach creates a new scope implicitly for you
    setTimeout(function() {
        console.log(number, i);
    },1000);
});

Protip:在诊断这样的事情时,我构建了我称之为“基准测试”的东西。在这里,您可以重新创建一个非常小的程序,重新创建您正在观察异常但没有无关代码的环境。带有超时的基本for循环是我经常用来试验异步代码的一个很好的例子。