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);
});
}
Ожидаемый результат:
http://google.com
http://yahoo.com
Фактический выход:
http://yahoo.com
http://yahoo.com
Итак, мой вопрос:
- Как передать URL (по значению) функции обратного вызова? ИЛИ
- Каков правильный способ связывания HTTP-запросов, чтобы они выполнялись последовательно? ИЛИ
- Что-то еще мне не хватает?
PS: Для 1. Я не хочу решение, которое проверяет параметры обратного вызова, но общий способ обратного вызова, зная о переменных "сверху".
Ответы
Ответ 1
Ваша переменная 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]);
}
Кстати, вложение a 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]);
}
Ответ 2
Отметьте этот блог. Переменная может быть передана с использованием метода .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}));
}
Ответ 3
См. fooobar.com/info/175249/... для общего обсуждения этой проблемы.
Я бы предложил что-то вроде
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));
}