简体   繁体   中英

JavaScript callback an array with values pushed through a loop

I have a Node.Js web app with Express.Js that reads values from xml files, store values from all xml files into an array with sub-array represent the separation of per xml file. At the moment, I have the following code on the Node:

app.get('/get_software_requests', function (req, res) {
console.log("loading software requests");
requests_callback(function(all_software_requests){
    console.log(all_software_requests);
});

function requests_callback(callback){
    loadAllSoftwareRequests(function(all_software_requests){
    callback(all_software_requests);
    });
 }
});

function loadAllSoftwareRequests(callback){
console.log("loading requests");
fs.readdir("/project_requests", function(error, files) {
    files.forEach(filename => {
        var software_request = new Array();
        loadSoftwareRequestXML(filename, software_request, function(software_request){
            all_software_requests.push(software_request);
            callback(all_software_requests);
        });
    });
 });
}

function loadSoftwareRequestXML(filename, software_request, callback){
var xmlparser = new xml2js.Parser();
var filepath = "/project_requests/" + filename;
fs.readFile(filepath, "utf-8", function(error, values){
    xmlparser.parseString(values, function(error, xmlfile){
        var xmldata = xmlfile;
        date_requested = xmldata.ProjectRequest.DateRequested;
        client_org = xmldata.ProjectRequest.ClientOrganization;
        proposed_budget = xmldata.ProjectRequest.ProposedBudget;
        contact_name = xmldata.ProjectRequest.ContactName;
        delivery_date = xmldata.ProjectRequest.DeliveryDate;
        requirements = xmldata.ProjectRequest.UserRequirements;
        software_request.push(date_requested);
        software_request.push(client_org);
        callback(software_request);
    });
 });
}

So far, for "console.log(all_software_requests);" on the main app.get, the console outputs:

在此处输入图片说明

I want the Node to only return the last iteration result, like

在此处输入图片说明

Any help or suggestion is appreciated. Please feel free to comment. Thanks.

You can use native promises for that:

Promise.all(files.map(
    filename => new Promise(ok => load(filename, request => ok(request)))
)).then(requests => callback(requests));

I mess with promise/callback style here to minify your code editions.
Better to use promises instead of callbacks in client code too.

Then it becomes just:

let loadAll = files => Promise.all(files.map(load));
let load = filename => {/*return some promise with result*/}

Without promises at all it is not too difficult:

let c = files.length; // initialize a counter
files.forEach(filename => {
    var software_request = new Array();
    loadSoftwareRequestXML(filename, software_request, function(software_request){
        all_software_requests.push(software_request);
        if(!--c) { // all async calls are finished
          callback(all_software_requests);
        }
    });
});

You could also add my "next" method that will handle the looping for you. This has worked well for me in these types of situations.

  app.get('/get_software_requests', function (req, res) {
    console.log("loading software requests");
    requests_callback(function(all_software_requests){
        console.log(all_software_requests);
    });

function requests_callback(callback){
    loadAllSoftwareRequests(function(all_software_requests){
    callback(all_software_requests);
    });
  }
});

function loadAllSoftwareRequests(callback){
console.log("loading requests");
fs.readdir("/project_requests", function(error, files) {
    files.forEach(filename => {
        var software_request = new Array();
        loadSoftwareRequestXML(filename, software_request, function(software_request){
            all_software_requests.push(software_request);
            callback(all_software_requests);
        });
    });
 });
}

function loadSoftwareRequestXML(filename, software_request, callback){
var xmlparser = new xml2js.Parser();
var filepath = "/project_requests/" + filename;
fs.readFile(filepath, "utf-8", function(error, values){
  var index = 0;
  var next = function () {
    if (index >= values.length) {
      callback(null, values);
      return;
    }
    var value = values[index];
    xmlparser.parseString(value, function(error, xmlfile){
      var xmldata = xmlfile;
      date_requested = xmldata.ProjectRequest.DateRequested;
      client_org = xmldata.ProjectRequest.ClientOrganization;
      proposed_budget = xmldata.ProjectRequest.ProposedBudget;
      contact_name = xmldata.ProjectRequest.ContactName;
      delivery_date = xmldata.ProjectRequest.DeliveryDate;
      requirements = xmldata.ProjectRequest.UserRequirements;
      software_request.push(date_requested);
      software_request.push(client_org);
      value.software_request = software_request;
      index++;
      next()
    });
  }
  next();
 });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM