我确定我的问题是基于对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
所以我的问题是:
PS:For 1.我不想要一个能够检查回调参数的解决方案,而是一个从上面知道变量的回调的一般方法。
答案 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));
}