这是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'));
}
});
});
}
答案 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循环是我经常用来试验异步代码的一个很好的例子。