Узел массива функций, использующий переменные из окружающей области - PullRequest
0 голосов
/ 28 июня 2018

Я пытаюсь сделать dns.reverse() в списке IP, используя async.parallel().

Код выглядит следующим образом:

var functions = [];
for (var i = 0; i < data.length; i++) {
    var ip = data[i].ip;
    var x = function(callback) {
        dns.reverse(ip, (err, hostnames) => {
            if (err) {
                log.error("Error resolving hostname for [" + ip + '] ' + err);
                return callback(null, err);
            }

            callback(null, hostnames);
        });
    };

    functions.push(x);
}

async.parallel(functions, (err, results) => {
    for(var i = 0; i < data.length; i++) {
        data[i]['hostnames'] = results[i];
    }

    handler(null, data);
});

То, что происходит, dns.reverse() вызывается с тем же ip (последний в массиве данных) для всех вызовов. Может быть, я делаю что-то не так. Может кто-нибудь объяснить, в чем моя ошибка?

Ответы [ 2 ]

0 голосов
/ 28 июня 2018

Благодаря @apokryfos я получил подсказку. Чтобы заставить код работать, мне просто нужно использовать let вместо var при объявлении ip.

        var functions = [];
        for (var i = 0; i < data.length; i++) {
            let ip = data[i].ip;
            var x = function(callback) {
                dns.reverse(ip, (err, hostnames) => {
                    if (err) {
                        log.error("Error resolving hostname for [" + ip + '] ' + err);
                        return callback(null, err);
                    }

                    callback(null, hostnames);
                });
            };

            functions.push(x);
        }
        async.parallel(functions, (err, results) => {
            for(var i = 0; i < data.length; i++) {
                data[i]['hostnames'] = results[i];
            }

            handler(null, data);
        });

Для тех, кто заинтересован в понимании, может быть полезно следующее: Как работают закрытия JavaScript?

0 голосов
/ 28 июня 2018

Первый обратный вызов выполняется после завершения цикла for, потому что он асинхронный. Значение ip будет тем, что указано в последней итерации цикла. Вы могли бы поместить console.log, чтобы понять, что на самом деле происходит.

Правильный способ сделать это может быть:

async.parallel(data.map(({ ip }) => callback => {
    dns.reverse(ip, callback)
}), (err, results) => {
    for (var i = 0; i < data.length; i++) {
       data[i]['hostnames'] = results[i];
    }

    handler(null, data);  
})

Создать новый массив функций на основе каждого ip. Каждая функция будет вызывать свой обратный вызов как dns.reverse.

Кроме того, может быть лучше вернуть новый массив данных, не изменяя данные внутри цикла:

(err, results) => {
  const result = data.map((data, index) => ({
      ...data,
      hostnames: results[index]
  })

  handler(null, result);  
})
...