For-loop и асинхронный обратный вызов в node.js? - PullRequest
21 голосов
/ 01 сентября 2011

Я новичок в JavaScript и в node.js. Я хочу перебрать каталог и добавить всю статистику файла (не другие каталоги) в массив. Как вы видите ниже, есть проблема с моим кодом, поскольку обратный вызов, вероятно, будет вызван после завершения цикла for, поэтому использование переменной «i» в методе обратного вызова не будет работать. Но как должен выглядеть код, чтобы приведенный ниже фрагмент работал? Это как-то связано с замыканиями?

Спасибо за помощь!

    fs.readdir(SYNCDIR, function(err1, files) {
        var filesOnly = [];

        if(!err1) {

            for(var i = 0; i < files.length; i++) {

                var imgFilePath = SYNCDIR + '/' + files[i];
                fs.stat(imgFilePath, function(stat){

                    if (stat.isFile()){
                        filesOnly[i] = stat; // This will not be correct since the for-loop has finished
                    }
                });

            }
        }
    });

Ответы [ 3 ]

32 голосов
/ 01 сентября 2011

Вы правы насчет необходимости использовать замыкание.Вам следует обернуть содержимое цикла for в самовозглашающуюся функцию, чтобы сохранить значение i для каждой итерации.

fs.readdir(SYNCDIR, function(err1, files) {
    var filesOnly = [];

    if(!err1) {

        for(var i = 0; i < files.length; i++) {

            (function(i) {
                var imgFilePath = SYNCDIR + '/' + files[i];
                fs.stat(imgFilePath, function(stat){
                    if (stat.isFile()){
                        filesOnly[i] = stat;
                    }
                });
            })(i);

        }
    }
});
10 голосов
/ 01 сентября 2011

Один из способов - переписать внутренности цикла для использования замыкания:

fs.readdir(SYNCDIR, function(err1, files) {
    var filesOnly = [];
    if(!err1) {
        for(var i = 0; i < files.length; i++) {
            (function(index) {
                var imgFilePath = SYNCDIR + '/' + files[index];
                fs.stat(imgFilePath, function(stat){
                    if (stat.isFile()){
                        filesOnly[index] = stat;
                    }
                });
            })(i);
        }
    }
});

Лучший пример с тем же достижением, используя Array.prototype.forEach:

fs.readdir(SYNCDIR, function(err1, files) {
    var filesOnly = [];
    if(!err1) {
        files.forEach(function(file, i) {
            var imgFilePath = SYNCDIR + '/' + file;
            fs.stat(imgFilePath, function(stat){
                if (stat.isFile()){
                    filesOnly[i] = stat;
                }
            });
        });
    }
});
0 голосов
/ 01 сентября 2011

В качестве альтернативы используйте модуль новых потоков (https://github.com/robtweed/Q-Oper8), и тогда вы сможете делать все это гораздо проще, используя стандартное синхронное кодирование в дочерних процессах потоков, поскольку они одновременно обрабатывают только один запрос пользователя.

Прощай, асинхронная логика и вложенные обратные вызовы!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...