我试图了解如何在这里调用http.get。以下是我试验的示例代码:
var http = require('http');
var urls = ['http://www.google.com',
'http://www.yahoo.com',
'http://www.cnn.com']
for (i = 0; i < 3; i++ ){
url = urls[i]
console.log(url)
console.log('------')
http.get(url, function(resp){
console.log(url)
});
};
上面的代码给出了这个输出:
http://www.google.com
------
http://www.yahoo.com
------
http://www.cnn.com
------
http://www.cnn.com
http://www.cnn.com
http://www.cnn.com
我得到了前三个(之前的那些&#39; ------&#39;)。我不明白的是,为什么最后三行都给我cnn.com?我认为每次迭代都会启动http.get请求?
这是否意味着http.get中的console.log(url)引用了http.get之外的url = urls [2],而对于&#39;到达循环的末尾?我如何打印网址,又称传递给http.get的参数?
答案 0 :(得分:1)
问题是你的url
变量是由所有回调函数共享的,因此在调用任何函数时最终保持它在循环中保留的最后一个值。为了澄清,下面的代码就是你将“解开”所有事情以适当的时间顺序发生的事情:
url = urls[0] // google
console.log(url) // google
http.get... // creates a function which captures a reference to 'url'
// but doesn't actually run anything
url = urls[1] // yahoo
console.log(url) // yahoo
http.get... // creates a second function with exactly the same ref
url = urls[2] // cnn
console.log(url) // cnn
http.get... // creates a *third* function with exactly the same ref
http... console.log(url) // the "google" callback is finally called after the GET
// finishes, but `url` now contains "...cnn..."
http... console.log(url) // the "yahoo" callback called, but of course prints cnn
http... console.log(url) // the "cnn" callback is called, and prints the expected
// value, but really only by chance
要解决此问题,您需要执行更多操作以捕获变量,以便每个函数都获得自己的副本。有几种方法可以做到这一点,但我个人使用:
makeResponseFunc = function(u) {
return function(response) {
console.log(u);
}
}
for (i = 0; i < 3; i++) {
url = urls[i];
http.get(url, makeResponseFunc(url));
}
基本上,makeResponseFunc
是创建函数的函数。参数u
由新创建的函数捕获,但由于每次调用makeResponseFunc
,都会创建一个新的u
,每个新创建的函数都会获得自己的副本。 (见Currying)。
正如我所提到的,有很多方法可以做到这一点,但我发现从语法的角度来看,这可以使事情变得简单。
答案 1 :(得分:0)
这与节点无关;这是一个javascript闭包问题。变量url
正在循环的每次迭代中更新,以便在执行任何回调函数(创建三个)时,url
变量设置为"http://www.cnn.com"
。
试试这个,这是获得所需输出的一种hacky方式:
var http = require('http');
var urls = ['http://www.google.com',
'http://www.yahoo.com',
'http://www.cnn.com']
for (i = 0; i < 3; i++ ){
(function() {
var url = urls[i]
console.log(url)
console.log('------')
http.get(url, function(resp){
console.log(url)
});
})();
};
基本上,它只是添加一个闭包,这样你就不会在每次迭代时修改相同的变量。
答案 2 :(得分:0)
基本上,是的,console.log(url)
内的http.get
指的是urls[2]
。您可以使用closure捕获当前url
以供日后使用,如下所示:
for (i = 0; i < 3; i++ ){
url = urls[i];
console.log(url);
console.log('------');
(function(url) {
http.get(url, function(resp){
console.log(url);
});
})(url);
}