Вызов асинхронной функции внутри для цикла

#javascript #node.js #asynchronous #for-loop #scope

#javascript #node.js #асинхронный #for-цикл #область

Вопрос:

 var path;

for (var i = 0, c = paths.length; i < c; i  )
{
    path = paths[i];

    fs.lstat(path, function (error, stat)
    {
        console.log(path); // this outputs always the last element
    });
}
  

Как я могу получить доступ к path переменной, которая была передана в функцию fs.lstat?

Ответ №1:

Это отличная причина использовать .forEach() вместо цикла for для итерации значений.

 paths.forEach(function( path ) {
  fs.lstat( path, function(err, stat) {
    console.log( path, stat );
  });
});
  

Кроме того, вы могли бы использовать замыкание, как предлагает @Aadit:

 for (var i = 0, c = paths.length; i < c; i  )
{
  // creating an Immiedately Invoked Function Expression
  (function( path ) {
    fs.lstat(path, function (error, stat) {
      console.log(path, stat);
    });
  })( paths[i] );
  // passing paths[i] in as "path" in the closure
}
  

Комментарии:

1. Будьте осторожны с . forEach, если ваш итерируемый не сформирован исключительно из элементов, которые вы хотите использовать. Я бы предпочел использовать опцию закрытия как общее правило, ИМХО.

2. @DanibISHOP не могли бы вы подробнее рассказать об этом? В частности, что такое «не исключительно сформированный с элементами»?

Ответ №2:

Классическая проблема. Поместите содержимое цикла for в другую функцию и вызовите ее в цикле. Передайте путь в качестве параметра.

Ответ №3:

Рекурсия здесь хорошо работает (особенно, если у вас есть некоторый ввод-вывод, который должен выполняться синхронно):

 (function outputFileStat(i) {
    var path = paths[i];

    fs.lstat(path, function(err, stat) {
         console.log(path, stat);
         i  ;
         if(i < paths.length) outputFileStat(i);
    });
})(0)