2

My objective is to read data from two files and compare the data. My input files are result3.json and result4.json.The data in these files are coma separated.

result3.json

[
  "temp1.txt",
  "temp2.txt",
]

node:

function readFromFile(file) {
    var fileNames = [];
    //setTimeout(function() {
        fs.readFile(file,function(err, data){
            if (err) {
                return console.log(err);
            }
            var temp = JSON.parse(data.toString().split(","));
            // console.log(temp.length);
            for (let index = 0; index < temp.length; index++) {
                //console.log(temp[index]);
                fileNames.push(temp[index]);
                //console.log(fileNames[index]);
            }
            Done(); // to block the async call
        });
        //},3000);
    //console.log(fileNames.length);
    return fileNames;
}

var baseListOfFiles = readFromFile('./output/result3.json'); // Assume this is the base file
var currentListOfFiles = readFromFile('./output/result4.json'); // Assume this is the current file

function Done(){
    //console.log('Out baseListOfFiles + ' + baseListOfFiles.length);
    for (let index = 0; index < baseListOfFiles.length; index++) {
        console.log("[baseListOfFiles] " + baseListOfFiles[index]);
    }

    //console.log('Out currentListOfFiles+ ' + currentListOfFiles.length);
    for (let index = 0; index < currentListOfFiles.length; index++) {
        console.log("[currentListOfFiles] " + currentListOfFiles[index]);
    }

}

Above is my code. It seems to be async call, so it always return 0 fileNames. Is there any way to control it?

daedsidog
  • 1,732
  • 2
  • 17
  • 36
Praveer Kumar
  • 912
  • 1
  • 12
  • 25
  • There are several ways to wait for multiple async calls to finish. See here: https://stackoverflow.com/questions/31413749/node-js-promise-all-and-foreach Also, if those files contain JSON, there's no need to use `toString()` or `split()` or any of that. –  Dec 18 '18 at 11:48

2 Answers2

9

Here's example code using Promises:

const fs = require('fs');

function readFromFile(file) {
    return new Promise((resolve, reject) => {
        fs.readFile(file, function (err, data) {
            if (err) {
                console.log(err);
                reject(err);
            }
            else {
                resolve(JSON.parse(data));
            }
        });
    });
}

const promises = [
    readFromFile('./output/result3.json'),
    readFromFile('./output/result4.json')
];

Promise.all(promises).then(result => {
    console.log(result);
    baseListOfFiles = result[0];
    currentListOfFiles = result[1];
    // do more stuff
});

First, an array promises is built; each Promise reads the file, then calls resolve with the result.
This array is passed to Promise.all(), which then calls the callback, passing the array of results in the same order.

2

You're right, readFile is async. What you're looking for is readFileSync: https://nodejs.org/api/fs.html#fs_fs_readfilesync_path_options

With that can can do:

const data = fs.readFileSync(file);

//do something with data

There are a few ways to 'promisify' readFile if you like, the options are discussed here: Using filesystem in node.js with async / await

Geraint
  • 3,314
  • 3
  • 26
  • 41
  • Thanks for your guidance. I will try this way – Praveer Kumar Dec 18 '18 at 11:53
  • @PraveerKumar use [util.promisify](http://2ality.com/2017/05/util-promisify.html) to wrap `fs.readFile()` into a promise then use async and await if you are using >= NodeJS v8. – Kunal Mukherjee Dec 18 '18 at 12:06
  • 1
    The other answer should be the preferred one actually. JS being asynch by nature, forcing the synch is not a good idea. Imagine the file read for both takes 1min, you don't want to wait 1+1= 2 mins, but instead wait 1min only that both have completed in parallel – goul May 22 '19 at 03:43