Search code examples
javascriptnode.jsasynchronousfsxml2js

Get async result in async.filter() array nodejs


Need to parse some XML files from mass array with file_path values. Try to use async, fs, xml2js. When use single string file_path all works perfect. But when I use aync.filter() with array I can't understand how I can return result from xml.parseString()

const fs = require('fs');
const xml2js = require('xml2js');
const async = require('async');

var mass=['/file1.xml','/fil2.xml','/file3.xml',...]

async.filter(mass, async function(file_path, callback){
    if(fs.statSync(file_path)['size']>0){
        fs.readFileSync(file_path, 'utf8', function(err, data) {        
            xml.parseString(data, function (err, result) {
               console.log(Object.keys(result)[0]);
               return result; //need get this result to results array
            })
        }) 
    }
}, function(err, results) {
    console.log(results)
});

Who can understand how it works and what I need to change in my code. Thanks a lot!


Solution

  • You are trying to map and filter at the same time. Since your filter condition is synchronously available, use the array filter method for that, and then pass that to async.map.

    You should then call the callback function, that async.map provides to you, passing it the result. So don't return it, but call the callback.

    The readFileSync method does not take a callback like its asynchronous counterpart. It just returns the data.

    Also, drop the async keyword, as you are not using the await keyword at all.

    async.map(mass.filter((file_path) => fs.statSync(file_path).size > 0), 
        function(file_path, callback){
            var data = fs.readFileSync(file_path, 'utf8');
            xml.parseString(data, function (err, result) {
               console.log(Object.keys(result)[0]);
               callback(null, result);
            }) 
        }, function(err, results) {
            console.log(results)
        }); 
    

    It should be noted however, that since Node now comes with the Promise API, and even the async/await extension to that, the async module has become much less interesting. Consider using Promises.

    const promises = mass.filter(file_path => {
        return fs.statSync(file_path).size > 0
    }).map(function(file_path) {
        return new Promise(resolve => {
            const data = fs.readFileSync(file_path, 'utf8');
            xml.parseString(data, function (err, result) {
                console.log(Object.keys(result)[0]);
                resolve(result);
            });
        }); 
    });
    Promise.all(promises).then(results => {
        console.log(results);
    });