1

I am very new to JavaScript and Node.js. What I am trying to do is use Node's filestream to read a bunch of images and js files from two different directories. I have written a fileReader.js module for reading images and .js files like below

var fs = require('fs');

//module to read all the images from the images directory --> either .jpg or .png images and filter out the rest
function readImages()
{
    var imageArray = [];
    fs.readdir('../images',function(err,files)
    {       
        files.filter(function(file)
        {
            return ( (file.substr(-4) === '.png') || (file.substr(-4) === '.jpg') );
        }).forEach(function(file)
        {
            imageArray.push(file);
        });
        console.log(imageArray);
        return imageArray;
    });
    //or return here???
}

//module to read all the javascript files and filter out non js files
function readJSFiles()
{
    var jsArray = [];
    fs.readdir('../jsfiles',function(err,files)
    {       
        files.filter(function(file)
        {
            return ( (file.substr(-3) === '.js') );
        }).forEach(function(file)
        {
            jsArray.push(file);
        });

        console.log(jsArray);
        return jsArray;
    });
    // or return here???
}

exports.readImages = readImages;
exports.readJSFiles = readJSFiles;

Now I am trying to return two different array objects one for list of images and other for list of js files. I want to use these objects in my main.js file so I call them like below in my main.js

var filereader = require('./fileReader');

var images = filereader.readImages();
var jsfiles = filereader.readJSFiles();

But these array objects are empty in the main.js file. From what I understand, this has something to do with callbacks but how do I go about solving this problem??

Htlcs
  • 545
  • 3
  • 13
  • 26
  • 4
    Use promises. http://blog.slaks.net/2015-01-04/async-method-patterns/ – SLaks Jan 19 '15 at 23:17
  • possible duplicate of [How to return value from an asynchronous callback function?](http://stackoverflow.com/questions/6847697/how-to-return-value-from-an-asynchronous-callback-function) – famousgarkin Jan 19 '15 at 23:25

1 Answers1

3

You don't want to set return values for these asynchronous functions. Instead, invoke a callback function once your fs method has completed.

function readImages(callback)
{
    var imageArray = [];
    fs.readdir('../images',function(err,files){       
        files.filter(function(file){
            return ( (file.substr(-4) === '.png') || (file.substr(-4) === '.jpg') );
        }).forEach(function(file){
            imageArray.push(file);
        });
        console.log(imageArray);

        //invoke the function from above
        callback(imageArray);
    });
}

You can write your readImages() function to accept a callback function. This callback function will set your images variable to point to the array of images.

//main.js
var filereader = require('./fileReader');
var images;

filereader.readImages(function(myImagesFromFs){
  images = myImagesFromFs;
});
Liam Schauerman
  • 851
  • 5
  • 10
  • That works!! thanks a lot. I am slightly confused with the solution. What is the flow of execution of functions here if you do not mind me asking? As far as I understand, whenever the readImages function is called from the main, it first executes all the inner callback functions and populates the array. Once this is done, the callback from the calling function gets called? In this case the callback inside the readImages function as a parameter gets called at the very end? Correct me if I am wrong :) – Htlcs Jan 19 '15 at 23:52
  • also the arrays only get populated inside the call back function calls. But what if I want to use them as global variables ie use images outside the readImages function call in the main.js? – Htlcs Jan 19 '15 at 23:57
  • the sequence is initiated when you invoke your readImages function. this creates a var imageArray, then calls fs.readdir. Once the directory has been read, the anonymous function (the second argument of readdir() ) is invoked, with access to the array of files. this is where files.filter is executed, etc. The last line of that anonymous function is where your custom callback gets executed. That function will be defined as the first argument of .readImages() – Liam Schauerman Jan 20 '15 at 00:11
  • If you want access to the results of an asynchronous function call (such as readdir), you need to assign some declared variable to those results inside the asynchronous function's callback, which will only be invoked once the results are ready – Liam Schauerman Jan 20 '15 at 00:13
  • Thanks again. I don't quite understand the explanation in your last comment. Would you mind writing a pseudo code for the same? Apologies as I am completely new to JavaScript and still trying to get a grip on callbacks, – Htlcs Jan 20 '15 at 00:34
  • Sure. Asynchronous functions will generally include a success callback in their definition. This is why readdir needs to be given a function in the arguments, like readdir(callback). the readdir function was designed such that the results of reading a directory are passed into the callback as an argument, along with any errors. – Liam Schauerman Jan 20 '15 at 00:45