Overhanding data to callbacks

Hej,

I'm experimenting with node.js and its callback mechanism. And now I wonder how to overhand data to such an anonymous callback:

var fs = require('fs');

for (var i = 0; i < 4; i++) {
    console.log('Outer: ' + i);
    fs.readFile('/etc/hosts', 'ascii', function(err, data) {
        console.log('Inner: ' + i);
    });
}

I do understand why the inner call to i returns 4 always. But how can I supply some variables to that specific readFile-callback function (so that the inner i will have the value of the outer i)? I could imagine some queue mechanism, where the callback function acts as a consumer, but as a node beginner I'd like to ask for the best practices. Thanks a lot,

mechko

With the pure Javascript (that is, not using libraries such as async):

var fs = require('fs');

var i,
    reader = function (i) {
        return function (err, data) {
            console.log('Inner: ' + i);
        }
    };

for (i = 0; i < 4; i++) {
    console.log('Outer: ' + i);
    fs.readFile('/etc/hosts', 'ascii', reader(i));
}

Or, alternatively,

var fs = require('fs');

var i;

for (i = 0; i < 4; i++) {
    console.log('Outer: ' + i);
    fs.readFile('/etc/hosts', 'ascii', function (i, err, data) {
        console.log('Inner: ' + i);
    }.bind(null, i));
}

(moving the var i; declaration out of the for loop does not really changes anything in this specific example, it is just a code style to prevent the bugs related to Javascript, as opposed to the programming languages like Java, having only the function scope for variables - so that, in your original example, i is declared for the entire module, not just for for loop).

Alternative approach would be to use libraries such as async and underscore like this:

var _ = require('underscore'),
    async = require('async'),
    fs = require('fs');

async.parallel(_.map(_.range(0, 4), function (i) {
    return async.waterfall.bind(null, [
        fs.readFile.bind(null, '/etc/hosts', 'ascii'),
        function (data, callback) {
            console.log("Inner: " + i);
            callback();
        }
    ]);
}, function (err) {
    if (err) {
        console.log("Some read attempt failed");
    } else {
        console.log("Done reading");
    }
});