2

I am currently new to Node JS, and today I was trying to read data from a file data.json.

Here is the JSON file:

{"username":"rahul_v7","password":"9673"} {"username":"7vik","password":"3248"} {"username":"pradypot_2","password":"6824"} {"username":"ad_1","password":"9284"} {"username":"premchand_4","password":"4346"} 

And, I was using the below code present in a file GetData.js, to read the data present in the data.json:

'use strict';
const fs = require('fs');

let res = '', resObjs = [];
let fin = fs.createReadStream('F:/RahulVerma/NodeJS/data.json', 'utf-8');
fin.on('data', data => {
    if(data.length > 0) res += data;
}).on('end', () => {
    if(res.length > 0) {
        let resArr = res.trim().split(' ');

        for(let i = 0; i < resArr.length; i++) {
            resObjs.push(JSON.parse(resArr[i]));
        }

        module.exports.objects = resObjs;
    }
});

As you can see, I am exporting the resObjs array, which is actually an array of objects, to an another file named AppendData.js, which is given below:

'use strict';
const fs = require('fs');
const getObjs = require('./GetData');

console.log(getObjs.objects);

But, when I run AppendData.js in Node.js 9.3.0 (ia32), it gives the following output:

Output Image

2 Answers2

2

You're trying to use the objects before they've been read. Remember that your code reading the stream runs asynchronously, and nothing in your code attempts to coordinate it with module loading. So AppendData.js isn't seeing the objects export because it doesn't exist yet as of when that code runs.

Instead, return a promise of the objects that AppendData.js can consume; see *** comments:

'use strict';
const fs = require('fs');

// *** Export the promise
module.exports.objectsPromise = new Promise((resolve, reject) => {
    let res = '', resObjs = [];
    let fin = fs.createReadStream('F:/RahulVerma/NodeJS/data.json', 'utf-8');
    fin.on('data', data => {
        if(data.length > 0) res += data;
    }).on('end', () => {
        if(res.length > 0) {
            let resArr = res.trim().split(' ');

            for(let i = 0; i < resArr.length; i++) {
                resObjs.push(JSON.parse(resArr[i]));
            }

            resolve(resObjs); // *** Resolve the promise
        }
    }).on('error', error => {
         reject(error);       // *** Reject the promise
    });
});

Note I added a handler for errors.

And then:

'use strict';
const fs = require('fs');
const getObjs = require('./GetData');

getObjs.objectsPromise
    .then(console.log) 
    .catch(error => {
        // Do something
    });

Again note the error handler.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • *(Doh! If you see `.error(error => {` near the end of the answer, hit refresh. Silly typo.)* – T.J. Crowder May 20 '18 at 17:26
  • Nice, it worked for me! But, can you provide me a callback version of the same? It would be awesome! –  May 20 '18 at 17:33
  • 1
    @Rahul - Simple callbacks are a poorer choice than promises, not least because a promise can be used by multiple consumers. Doing this with a simple callback would actually be more complicated. – T.J. Crowder May 20 '18 at 17:34
1

The problem happens because you're trying to use the objects in AppendData.js before they are loaded on GetData.js due to fs.createReadStream being asynchronous. To fix this just make module.exports be a function that expect a callback in GetData.js like:

'use strict';
const fs = require('fs');

module.exports = function(callback) {
    let res = '', resObjs = [];
    let fin = fs.createReadStream('F:/RahulVerma/NodeJS/data.json', 'utf-8');
    fin.on('data', data => {
        if(data.length > 0) res += data;
    }).on('end', () => {
        if(res.length > 0) {
            let resArr = res.trim().split(' ');

            for(let i = 0; i < resArr.length; i++) {
                resObjs.push(JSON.parse(resArr[i]));
            }

            callback(resObjs);                        // call the callback with the array of results
        }
    });
}

Which you can then use like this in AppendData.js:

'use strict';
const fs = require('fs');
const getObjs = require('./GetData');                 // getObjs is now a function

getObjs(function(objects) {
    console.log(objects);
});
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73