Добавить дополнительные параметры в функцию обратного вызова - PullRequest
5 голосов
/ 14 мая 2011

Я создаю систему в Node.js, которая должна находить все файлы в массиве папок, оценивать их, а затем выполнять дополнительную работу, используя эту информацию.

Я использую fs.readdir (), чтобы получить все файлы синхронно из каждой папки.Мой код выглядит следующим образом:

for(i=0,max=paths.length; i<max; i++) {
    var path = paths.pop();
    console.log("READING PATH: " + path);
    fs.readdir(path, function(err, files) { handleDir(err, files, path); });
}

Проблема в том, что в зависимости от того, как быстро выполняется readdir (), handleDir () получает неправильный путь.Это происходит потому, что к тому времени, когда выполняется обратный вызов, следующий цикл уже начался - это означает, что переменная пути изменилась.

Итак, мне нужно как-то привязать эту переменную пути к ее конкретной функции обратного вызова.Я не могу придумать какой-либо хороший способ сделать это - у кого-нибудь есть идеи?

Ответы [ 5 ]

8 голосов
/ 14 мая 2011

Нет области видимости блока, поэтому используйте функцию для области.

for(var i=0, path, max=paths.length; i<max; i++) {
    path = paths.pop();
    console.log("READING PATH: " + path);
    handlePath( path );
}
function handlePath ( path ) {
    fs.readdir(path, onPathRead);
    function onPathRead (err, files) {
        handleDir(err, files, path);
    }
}
6 голосов
/ 14 мая 2011

Это одна из самых раздражающих частей JS для меня. Альтернатива созданию отдельной функции (как продемонстрировал @generalhenry) - заключить код в анонимную функцию, которая выполняется до изменения переменной пути.

for(i=0,max=paths.length; i<max; i++) {
    var path = paths.pop();
    console.log("READING PATH: " + path);
    fs.readdir(path,
        (function(p){
            return function(err, files) {
                handleDir(err, files, p);
            };
        })(path);
    );
}

В любом случае, важным моментом является то, что контекст функции (анонимный или нет) инициируется до переназначения значения переменной пути.

1 голос
/ 14 мая 2011

Это действительно раздражающая особенность Javascript, настолько, что Coffeescript (это язык, который компилируется в Javascript) имеет особый способ работы с ним, оператор do на for.В Coffeescript ваша оригинальная функция будет выглядеть так:

for path in paths
     fs.readdir path, (err, files) -> handleDir(err, files, path)

, а решение вашей проблемы будет:

for path in paths
   do (path) ->
     fs.readdir path, (err, files) -> handleDir(err, files, path)
0 голосов
/ 07 июня 2019

Отличное решение от generalhenry, но будьте осторожны, если вы собираетесь использовать структуру try / catch внутри функции обратного вызова.

function handlePath ( path ) {
    fs.readdir(path, onPathRead);
    function onPathRead (err, files) {
        try {
            handleDir(err, files, path);
        } catch (error) {
            var path = 'something_else'; // <<--- Never do this !!!
        }     
    }
}

Никогда не пытайтесь повторно объявить одну и ту же переменную в блоке catch, даже еслиблок catch никогда не вызывается, путь var сбрасывается, и вы найдете его как «неопределенный» при выполнении обратного вызова.Попробуйте этот простой пример:

function wrapper(id) {
    console.log('wrapper id:' + id);
    setTimeout(callback, 1000);
    function callback() {
        try {
            console.log('callback id:' + id);
        } catch (error) {
            var id = 'something_else';
            console.log('err:' + error);
        }
    }
}

wrapper(42);

Это выдаст:

wrapper id:42
callback id:undefined
0 голосов
/ 18 января 2017

Я искал то же самое и в итоге нашел решение, и вот простой пример, если кто-то хочет пройти через это.

var FA = function(data){
   console.log("IN A:"+data)
   FC(data,"LastName");
};
var FC = function(data,d2){
   console.log("IN C:"+data,d2)
};
var FB = function(data){
   console.log("IN B:"+data);
    FA(data)
};
FB('FirstName')
...