2015-04-11 6 views
0

Введите код для nodejs. Если я регистрирую значение переменной «i» в обратном вызове response.on («end»), он три раза печатает номер «2». Я не понимаю почему.Как определить текущий номер итерации в обратном вызове (nodejs)

var http = require('http'), 
     urls = [], 
     requestsDone = 0, 
     result = []; 

    for (var i in process.argv) { 
     if (i > 1) { 
      urls.push(process.argv[i]); 
     } 
    } 

    for (var i in urls) { 

     var nextUrl = urls[i]; 
     http.get(nextUrl, function(response){ 
      var allData = ''; 
      response.on("data", function(data){ 
       allData += data; 
      }); 

      response.on("end", function(){ 
       console.log(i); 
       result[requestsDone] = allData; 
       requestsDone +=1; 
       if (requestsDone == 3) { 
        console.log(result.join('\n')); 
       } 
      }); 
     }); 
    } 

ответ

1

Использование forEach (вместо for (var i in urls)), который создает новую область:

urls.forEach(function(nextUrl, i) { 
    http.get(nextUrl, function(response) { 
    ... 
    }); 
}); 
0

Ответ происходит потому, что http.get вызов является асинхронным.

Цикл итерации for проходит от 0 до urls.length в мгновение ока, так как он не поддерживается асинхронным кодом. С другой стороны, код, который выполняется внутри события end callback, называется long после того, как итератор выполнил итерацию с 0 до urls.length, поэтому любой вызов console.log(i) выведет свое окончательное значение, так как оно достигло этого значения задолго до выполнения оператора журнала.

Решение robertkelp разумно, создание нового закрытия (сферы) - это путь сюда.

Theres простой пример, чтобы продемонстрировать, что вы видите:

var array = [0,1,2,3,4,5,6,7,8,9]; 
for(i in array) { 
    setTimeout(function() { //simulating the async nature of the http.get call 
     console.log(array[i], i); 
    }, 1000); 
} 

Выведется 9 9 10 раз, это то, что вы видите.

Создание сферы и передача i обеспечит значение i захватывается, вот самый простой подход:

var array = [0,1,2,3,4,5,6,7,8,9]; 

function log(i) { 
    setTimeout(function() { 
     console.log(array[i], i); 
    }, 1000); 
} 

for(i in array) { 
    log(i); //creating a new scope and capturing the value of i 
} 

и более зрелый подход (с использованием того же Foreach итератора, как robertkelp предлагает)

var array = [0,1,2,3,4,5,6,7,8,9]; 

array.forEach(function(number, i) { //forEach creates a new scope implicitly for you 
    setTimeout(function() { 
     console.log(number, i); 
    },1000); 
}); 

Protip: При диагностике таких вещей я построить то, что я называю "стендовое испытание. Здесь вы воссоздаете очень маленькую программу, которая воссоздает среду, в которой вы наблюдаете аномалию, но без постороннего кода. Базовый для цикла с тайм-аутом - хороший пример, который я часто использую для экспериментов с асинхронным кодом.

Смежные вопросы