Добавить дополнительные параметры для функции обратного вызова
Я создаю систему в 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() получает неправильный путь. Это происходит потому, что к моменту завершения обратного вызова следующий цикл уже запущен - это означает, что изменена переменная пути.
Итак, что мне нужно сделать, это как-то заблокировать эту переменную пути для конкретной функции обратного вызова. Я не могу придумать какой-либо хороший способ сделать это - у кого есть идеи?
Ответы
Ответ 1
Нет области блока, поэтому используйте функцию для области.
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);
}
}
Ответ 2
Это одна из самых раздражающих частей 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);
);
}
В любом случае важным является то, что контекст функции (анонимный или нет) инициируется до того, как значение переменной пути будет переназначено.
Ответ 3
Это действительно раздражающая особенность 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)
Ответ 4
Я искал одно и то же, и в итоге получилось решение, и вот это простой пример, если кто-то хочет пройти через это.
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')
Ответ 5
Отличное решение от 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 !!!
}
}
}
Никогда не пытайтесь повторно объявить один и тот же var в блоке catch, даже если блок catch никогда не вызывается, путь var сбрасывается, и вы найдете его как "undefined" при выполнении обратного вызова. Попробуйте этот простой пример:
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