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

Mar*_*arc 42 javascript asynchronous web-crawler node.js

我确定我的问题是基于对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);
    });
}
Run Code Online (Sandbox Code Playgroud)

预期产量:

http://google.com
http://yahoo.com
Run Code Online (Sandbox Code Playgroud)

实际产量:

http://yahoo.com
http://yahoo.com
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:

  1. 如何将url(按值)传递给回调函数?要么
  2. 链接HTTP请求以便顺序运行的正确方法是什么?要么
  3. 我还缺少什么?

PS:对于1.我不想要一个检查回调参数的解决方案,而是一个回调知道变量'从上面'的一般方法.

Joh*_*yHK 49

您的url变量没有作用于for循环,因为JavaScript仅支持全局和函数作用域.因此,您需要为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]);
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,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]);
}
Run Code Online (Sandbox Code Playgroud)

  • 这不是关于范围.这是关闭.许多其他语言没有块范围,但由于缺少闭包而没有遇到此问题. (3认同)
  • 关键是如果JavaScript确实支持块作用域,那么在OP代码的回调函数中对`url`的闭包访问将起作用,因为循环的每次迭代都会得到它自己的`url`变量(就像在C#中一样). (3认同)

小智 9

查看此博客.可以使用.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}));
}
Run Code Online (Sandbox Code Playgroud)

  • 我更喜欢这种方法,因为它比在函数中包装一些东西要简洁得多。 (2认同)

Bob*_*obS 8

有关此问题的一般性讨论,请参阅/sf/answers/822313201/.

我建议像

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));
}
Run Code Online (Sandbox Code Playgroud)