了解nodejs中的http.get请求

时间:2014-08-02 03:52:25

标签: node.js

我试图了解如何在这里调用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的参数?

3 个答案:

答案 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);
}