Подтвердить что ты не робот

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. Я не хочу решение, которое проверяет параметры обратного вызова, но общий способ обратного вызова, зная о переменных "сверху".

4b9b3361

Ответ 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));
}