Node.JS:如何将变量传递给异步回调?

时间:2012-11-04 18:59:49

标签: javascript node.js asynchronous web-crawler

我确定我的问题是基于对node.js中的异步编程缺乏了解,但这里有。

例如:我有一个我想要抓取的链接列表。当每个异步请求返回时,我想知道它是用于哪个URL。但是,大概是因为竞争条件,每个请求返回的URL都设置为列表中的最后一个值。

var links = ['http://google.com', 'http://yahoo.com'];
for (link in links) {
    var url = links[link];
    require('request')(url, function() {
        console.log(url);
    });
}

预期产出:

http://google.com
http://yahoo.com

实际输出:

http://yahoo.com
http://yahoo.com

所以我的问题是:

  1. 如何将url(按值)传递给回调函数? OR
  2. 将HTTP请求链接起来以便顺序运行的正确方法是什么? OR
  3. 我还缺少什么?
  4. PS:For 1.我不想要一个能够检查回调参数的解决方案,而是一个从上面知道变量的回调的一般方法。

3 个答案:

答案 0 :(得分:48)

由于JavaScript仅支持全局和函数作用域,因此url变量的范围不限于for循环。因此,您需要为request调用创建一个函数作用域,以便通过使用立即函数捕获循环的每次迭代中的url值:

var links = ['http://google.com', 'http://yahoo.com'];
for (link in links) {
    (function(url) {
        require('request')(url, function() {
            console.log(url);
        });
    })(links[link]);
}
顺便说一句,在循环中嵌入require并不是一种好习惯。它可能应该重写为:

var request = require('request');
var links = ['http://google.com', 'http://yahoo.com'];
for (link in links) {
    (function(url) {
        request(url, function() {
            console.log(url);
        });
    })(links[link]);
}

答案 1 :(得分:9)

检查此blog。可以使用.bind()方法传递变量。在你的情况下,它将是这样的:

var links = ['http://google.com', 'http://yahoo.com'];
for (link in links) {
var url = links[link];

require('request')(url, function() {

    console.log(this.urlAsy);

}.bind({urlAsy:url}));
}

答案 2 :(得分:8)

有关此问题的一般性讨论,请参阅https://stackoverflow.com/a/11747331/243639

我建议像

var links = ['http://google.com', 'http://yahoo.com'];

function createCallback(_url) {
    return function() {
        console.log(_url);
    }
};

for (link in links) {
    var url = links[link];
    require('request')(url, createCallback(url));
}