Первый обратный вызов выполняется после завершения цикла 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);
})