metraon
metraon

Reputation: 1259

node.js Wait for task to be finished

So I am writing this node.js program to import XML files into arrays of JSON objects. I got 2 files to import, teachers.xml and students.xml.

Teachers and student contains several thousands of info about teachers and students. I got that part pretty well covered with my code.

This is my javascript file for parsing the files :

var fs = require('fs');
var xmldom = require('xmldom');
var async = require('async');

// Parse `catalog` xml file and call `callback(catalog domxml root)`
function parse_catalog(catalog, callback) {
    // Read xml file content
    fs.readFile(catalog, function (err, data) {
        if (err) {
            throw 'Error reading XML catalog';
        } else {
            // Parse xml content and return dom root
            var domRoot = new xmldom.DOMParser().parseFromString(data.toString());
            // Call callback passing dom root
            callback(domRoot)
    }
});
}

I got two methods like this to convert the xml to json and its working perfectly (one for teachers and one for students)

// Convert teacher XML into json format in a array
function convert_teachers(domCatalog) {
    var teachers = domCatalog.getElementsByTagName('teacher');
    var teachers_arr= [];
    for (var i = 0; i < teachers .length; i++) {
        var teacher= teachers[i];
        ...
        //Reading the xml 

        teachers_arr.push({
        ...
        //Create the json

        });
    }
    console.log("Teachers are now in JSON format ");
}

So in the end all I have to do is this :

parse_catalog('teachers.xml', convert_teachers);

When I do this :

parse_catalog('teachers.xml', convert_teachers);
parse_catalog('students.xml', convert_students);

One or the other will finish first depending on the number of elements to import, witch is normal I think.

What I want is to wait for both to be imported and then do some javascript manipulations and this is where I am stuck.

I tried to do this with async, but it doesnt not wait until the two files are finished to import.

async.parallel([
    function(callback) {
        parse_catalog('teachers.xml', convert_teachers);
        callback();
    },

    function(callback) {
        parse_catalog('students.xml', convert_students);
        callback();
    }
], function(err) { 
    if (err) return next(err);

    console.log("Finished");
    //Enventually some Javascript manipulations on the two arrays

});

Actually it outputs :

Finished
Teachers are now in JSON format
Students are now in JSON format

or depending of the file size

Finished
Students are now in JSON format
Teachers are now in JSON format

What I would like is more like :

Teachers are now in JSON format (or students)
Students are now in JSON format (or teachers)
Finished

I plan to load 2 more files, and the order they will be loaded doesn't matter to me.

Any leads ? Thanks!

Upvotes: 0

Views: 938

Answers (1)

mscdex
mscdex

Reputation: 106698

You're executing callback() in your async.parallel() functions too soon because by that time fs.readFile() hasn't even started yet. Try something like this instead:

function parse_catalog(catalog, callback) {
  // Read xml file content
  fs.readFile(catalog, function(err, data) {
    if (err)
      return callback(err);

    // Parse xml content and return dom root
    var domRoot = new xmldom.DOMParser().parseFromString(data.toString());

    // Call callback passing dom root
    callback(null, domRoot);
  });
}

// Convert teacher XML into json format in a array
function convert_teachers(domCatalog) {
  var teachers = domCatalog.getElementsByTagName('teacher');
  var teachers_arr = [];
  for (var i = 0; i < teachers .length; i++) {
    var teacher = teachers[i];
    ...
    //Reading the xml 

    teachers_arr.push({
    ...
    //Create the json

    });
  }
  console.log('Teachers are now in JSON format');
  return teachers_arr;
}
// and similarly for `convert_students`

async.parallel({
  teachers: function(callback) {
    parse_catalog('teachers.xml', function(err, domCatalog) {
      if (err)
        return callback(err);
      var teachers = convert_teachers(domCatalog);
      callback(null, teachers);
    });
  },
  students: function(callback) {
    parse_catalog('students.xml', function(err, domCatalog) {
      if (err)
        return callback(err);
      var students = convert_students(domCatalog);
      callback(null, students);
    });
  }
}, function(err, results) { 
  if (err) return next(err);

  console.log('Finished');

  // here you have `results.teachers` and `results.students`
  console.dir(results);
});

Upvotes: 1

Related Questions