1

I wrote an example code following.

//test.js
var fs = require('fs');
fs.readdir(__dirname+'/app/img/', function(err, files) {
    console.log(files);
});

someFunction(function(output){
    console.log(output);
});

console.log('This is the final console call');

function someFunction(callback) {
    callback(' I am some funciton. '); 
}

Then, after runing 'node test.js', I got following result.

$ node test2.js 
 I am some funciton. 
This is the final console call
[ 'photo1', 'photo2' ]

someFunction() is created by myself for simulating the callback function in fs.readdir(). And as my original assumption, the result should be

[ 'photo1', 'photo2' ]
 I am some funciton. 
This is the final console call

or

This is the final console call
[ 'photo1', 'photo2' ]
 I am some funciton. 

But now, logs of fs.readdir() and someFunction() appear before and after the log of final call log seperately.

hmmm.... I totally can't figure out it.


Therefore, my problem is that:

Why is the log from fs.readdir() is the last log?

Is it jsut because that fs.readdir() needs more time to execute?

Or, it's that I'm lack of some important concept about this issue?

Thanks you~!

Yes
  • 107
  • 2
  • 5
  • 1
    I guess on "it is just because..."... always good to have that: http://www.impressivewebs.com/callback-functions-javascript/. – loveNoHate Jun 29 '14 at 21:50
  • 1
    The important concept you're missing is **asynchrony**. [Some functions](http://stackoverflow.com/q/13806695/1048572) call their callbacks asynchronously. Your `someFunc` does not. – Bergi Jun 29 '14 at 21:55

2 Answers2

2

The fs.readdir function is executed async while the other two are not. This means that the function in fs.readdir will be executed later when the all the directory has been read(which could take a while).

The other two statements are executed sync which means they will run directly. Therefor they are printed before the files list.

Bubbad
  • 191
  • 1
  • 1
  • 10
2

The whole point of the async NodeJS interfaces is that you can keep running your program without needing to wait for long-latency functions such as readdir to return the results. You call eraddir to tell it to start processing, continue running your program and when readdir its done it will arrange to call the callback function you passed. If you call more than one async function at the same time there is no guarantee as to which one will finish first.

If you wanted all those console.logs to functions to execute sequentially you would need to nest the callbacks

var fs = require('fs');

function someFunction(callback) {
    callback(' I am some funciton. '); 
}

fs.readdir(__dirname+'/app/img/', function(err, files) {
    console.log(files);
    someFunction(function(output){
        console.log(output);
        console.log('This is the final console call');
    });    
});

A way with slightly better latency is to do all the calls at once and then wait until everything is done to print the results.

// receives an array of computations to run in parallel
// calls a callback with an array with the results when all computations are done
// each computation is a function that takes a return callback as its first parameter.
function parallel(computations, callback){
    var results = [];
    var n = 0;

    computations.forEach(function(comp, i){
        comp(function(result){
            n++;
            results[i] = result;
            if(n === computations.length){
                callback(results);
            }
         });
    });
}

var fs = require('fs');

function someFunction(callback) {
    callback(' I am some funciton. '); 
}

parallel([
    function(cb){
        fs.readdir(__dirname+'/app/img/', function(err, files) {
            cb(files);
        });
    },
    function(cb){
        someFunction(function(output){
            cb(output);
        });
    },
], function(results){
    console.log(results[0]);
    console.log(results[1]);
    console.log("This is the final console call");
});

I wouldn't recommend coding this kind of parallel synchronization by hand though. There are many async programming libraries out there to make the process more pleasant that offer this and much more.

hugomg
  • 68,213
  • 24
  • 160
  • 246
  • Thanks for your example. It looks very clear! Ya I know there is 'async' in npm. But I wanna figure out this issue totally before just using library to solve the problem. That's why I came here, and thanks again! – Yes Jun 29 '14 at 22:18
  • Hmm, I wonder which one is more clear for you then. [this earlier revision](http://stackoverflow.com/revisions/24480644/2) that does things the low level but brittle way or the current revision that implements a parallelization function symilar to the one in `async` – hugomg Jun 29 '14 at 22:21
  • Wow, you are cool haha. For me, the earlier is a basic & **straightforward** solution. I mean, if I need to write this feature by myself, it's almost what I can imagine. But I know there must be some smarter solution with better structure and flexibility, then, you just show me that, and also a clear code again. Therefore, I think these 2 are all clear for me. But much more important is that, with these 2 versions, it can make me thinking about the concept/solution step by step from low level to high. So both are goooooood and required for me! – Yes Jun 29 '14 at 23:18