Итак, я по-прежнему переношу приложение Python на Node.js по разным причинам. У меня есть умеренные знания Javascript через веб-разработку, но у меня есть некоторые проблемы с переменной областью действия и (возможно?) Некоторые асинхронные вызовы, которые я делаю.Область переменной в структуре вложенных функций «Класс» в Javascript
Итак, у меня есть вложенный метод «xmlToObjectByType» в моем классе DataLoader, который я пытаюсь потенциально установить для переменных в зависимости от некоторых критериев соответствия в серии XML-файлов. Независимо от того, что я делаю в методе, продукты никогда не меняются от нуля, а вызов xml_files.splice() никогда не работает. Я уверен, что это проблема с областью определения (код внутри parseString, который находится внутри fs.readFile, который находится внутри forEach и т. Д.), но я не смог найти много удачи, выясняя, почему и как правильно получить значение.
В качестве последнего канава я попытался получить результат в обратном вызове, заданном на xmlToObjectByType, который получает мне значение, которое я ищу, но я все еще не могу установить значение products
из обратного вызова. Я уверен, что это связано с определением области обзора, но я немного потеряю. Я уверен, что это очень простая вещь, которую я пропускаю, но прошло много времени с тех пор, как я глубоко погрузился в JS. Что совсем не так глубоко. Любые мысли о том, что я делаю неправильно здесь, кроме, вероятно, ужасного логического потока?
Обратите внимание, что это упрощенная версия, где я вынул проверки для нескольких других типов файлов XML по причинам разборчивости.
Код
var fs = require('fs'),
xml2js = require('xml2js');
export function DataLoader(working_directory){
var working_directory = working_directory;
var xml_files = [];
var products = null;
var data = null;
var xmlToObjectByType = function(type, setValue) {
xml_files.forEach(function(file, index) {
var parser = new xml2js.Parser();
fs.readFile(working_directory + '/' + file, function(err, data) {
parser.parseString(data, function (err, result) {
if (result.Products.Product) {
var result_object = result.Products.Product;
// check if we've got at least one row, else return false
if (result_object.length > 0) {
// products specific check
if (type == "products") {
// identify products XML with artist tag
if (result_object[0].Artist) {
// this is a products XML file, so pop this file from xml_files, return object
xml_files.splice(index, 1);
setValue(result_object);
}
}
} else {
// no rows in object
setValue("no rows");
}
} else {
// ROW object isn't set, malformed XML
setValue("malformed XML");
}
});
});
})
}
// check selected directory for XML files
fs.readdir(working_directory,function(err,files){
if(err) throw err;
files.forEach(function(file){
// do something with each file HERE!
if (file.split('.').pop() == "xml") {
xml_files.push(file);
}
});
// if they don't exist return and send message
if (xml_files.length < 1) {
var status = {status: "error", message: "There are no XML files in the directory you selected."};
} else {
// process further
xmlToObjectByType("products", function(result) {
products = result;
});
data = {"products": products};
// products always has the value null here
console.log(data);
}
return status;
});
};
Я звоню его через
import { DataLoader } from './my_module';
DataLoader('/Path/To/XML');
И упрощенный пример файла XML (я думаю, что я сделал это право)
<?xml version="1.0" encoding="UTF-8" ?>
<Products>
<Product>
<Artist>Test</Artist>
<Title>Test Title</Title>
<Description>Maecenas faucibus mollis interdum. Donec sed odio dui. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Aenean lacinia bibendum nulla sed consectetur. Cras mattis consectetur purus sit amet fermentum.</Description>
</Product>
<Product>
<Artist>Test</Artist>
<Title>Test Title</Title>
<Description>Maecenas faucibus mollis interdum. Donec sed odio dui. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Aenean lacinia bibendum nulla sed consectetur. Cras mattis consectetur purus sit amet fermentum.</Description>
</Product>
<Product>
<Artist>Test</Artist>
<Title>Test Title</Title>
<Description>Maecenas faucibus mollis interdum. Donec sed odio dui. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Aenean lacinia bibendum nulla sed consectetur. Cras mattis consectetur purus sit amet fermentum.</Description>
</Product>
<Product>
<Artist>Test</Artist>
<Title>Test Title</Title>
<Description>Maecenas faucibus mollis interdum. Donec sed odio dui. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Aenean lacinia bibendum nulla sed consectetur. Cras mattis consectetur purus sit amet fermentum.</Description>
</Product>
</Products>
Так что, похоже, я пропустил асинхронные подсказки на нескольких уровнях. Это полностью имеет смысл и работает. Единственное, на что я немного расплывчато, и я не упоминаю в этом вопросе ради краткости: я на самом деле в конечном итоге вызываю xmlToObjectByType три раза для трех разных типов файлов типа XML; задаваясь вопросом, есть ли разумный способ запустить обратный вызов с результатами всех трех вызовов xmlToObjectByType после их увольнения ... моя первоначальная мысль заключается в том, что вызовы xmlToObj внутри обратного вызова, но я могу понять, почему это явно не сработает. –
Похоже, вы задаете себе правильные вопросы. Чтобы получить то, что вам нужно, вы должны знать, какие области вы создаете, когда они создаются и когда они дают результаты. Именно здесь асинхронный мир может сначала отключить людей. Это требует небольшой корректировки. То, что я сделал, обновлено моим ответом с переписанием вашего модуля, который поместит второй груз данных XML в возвращаемые данные. Если вы можете попытаться собрать его, он должен продемонстрировать, как вы можете столкнуться с проблемами сферы/асинхронности в будущем. – shennan
Ничего себе, спасибо за это - не нужно, но приятно видеть. Это полностью имеет смысл, как обратный вызов контактирует с функциями, а также имеет смысл, почему он может отбросить кого-то. Очень признателен! –