目标是创建不同的函数,分离加载多个(xml)文件并解析它们的工作。我可以在一个函数中完成所有操作,但嵌套的回调开始变得丑陋。换句话说,我不想要这样做:
// Explore directory
fs.readdir(path, function (err, files) {
if(err) throw err;
// touch each file
files.forEach(function(file) {
fs.readFile(path+file, function(err, data) {
if (err) throw err;
someAsyncFunction ( function (someAsyncFunctionResult) {
// Do some work, then call another async function...
nestedAsynchFunction ( function (nestedAsyncFunctionResult) {
// Do Final Work here, X levels deep. Ouch!
});
});
});
});
});
相反,我想要一个函数来读取我的文件并将每个文件的XML有效负载放入一个对象数组中,然后返回给调用者(每个对象代表文件的名称和文件中的XML) 。这是可能将报告加载到数组中的函数:
function loadReports (callback) {
var path = "./downloaded-reports/";
var reports = [];
// There are TWO files in this path....
fs.readdir(path, function (err, files) {
if(err) throw err;
files.forEach(function(file) {
fs.readFile(path+file, function(err, data) {
if (err) throw err;
reports.push({ report: file, XML: data.toString()});
//gets called twice, which makes for strangeness in the calling function
callback(null, reports);
});
});
// callback won't work here, returns NULL reports b/c they haven't been processed yet
//callback(null, reports);
});
}
...这里的功能将调用上面的那个:
function parseReports() {
loadReports( function(err, data) {
console.log ("loadReports callback");
var reportXML = new jsxml.XML(data[0].XML);
var datasources = reportXML.child('datasources').child('datasource').child('connection').attribute("dbname").toString();
console.log(JSON.stringify(datasources,null, 2));
// More async about to be done below
} );
}
正如您在loadReports()注释中看到的那样,我无法使回调正常工作。它要么在数组完全填充之前回调,要么回调两次 - 每次fs.readFile操作一次。
那么......处理这种情况的最佳方法是什么?简而言之 - 对于一个异步处理多个事物的函数来说,最好的设计模式是什么,所以它只能在所有"事物"已经完全处理?越简越好。我是否需要使用某种排队模块,如Q或node-queue?
非常感谢!
编辑:这样的事情在最深的循环中起作用,没有两次回击,但它看起来像一个kludge:
fs.readdir(path, function (err, files) {
if(err) throw err;
files.forEach(function(file) {
fs.readFile(path+file, function(err, data) {
if (err) throw err;
reports.push({ report: file, XML: data.toString()});
// WORKS, but seems hacky.
if (reports.length = files.length) callback(null, reports);
});
});
});