NodeJS + redis gives weird results

296 Views Asked by At

Maybe the results ain't weird, but I started using Node 1-2 months ago so for me they are...

I have a loop which sorts out every other value of the array returned by hgetall (Redis command) and in that loop I call a function to get all values from another table with keys stored in the sorted array. This was more difficult to explain than I thought. Here's my code:

Pastebin: http://pastebin.com/tAVhSUV1 (or see below)

function getInfo (cn, callback) {
        var anArray = [];
        redis_client.hgetall('chat_info:' + cn, function (err, vals) {
                if(err) { throw err; }
                for(i in vals) {
                        anArray.push(vals[i]);
                }
                return callback(anArray);
        });
}

redis_client.hgetall('chat_rooms:' + POST.chat_name, function (err, val) {
        if(err) { throw err; }
        var     vars = [],
                rArr = [];

        for (i in val) {
                vars.push(i);
        }
        for(var i = 0; i < vars.length; i += 1) {
                if(i%2 === 0) {
                        getInfo(vars[i], function (hej) {
                                rArr.push(hej);
                        });
                }
        }      
});

The callback from the call to getInfo() is executed after the entire loop. Am I missing out on something here? Because it can't do that, right? (when I use rArr (right after the loop) it's empty, nbBut if I log it in the callback it gets logged after everything else written after the loop)

1

There are 1 best solutions below

4
On

Yes, that's probably normal.

Understand that callbacks are executed after the hgetall call. Which mean that when the redis functions receive somehting it will call the callbacks. In other words, all the callbacks can be executed later.

As javascript only works in one thread, the calls to hgetall should be blocking to be executed as they come in the for loop. But as you're more certainly using async IO. The for loop ends and then it will start calling each callbacks that were queued inside the javascript event loop.

Edit

Unfortunately, to achieve what you're trying to do, you should wrap your code inside many other callbacks. You can use this project to make it easier: https://github.com/caolan/async

You should be able to install it using npm install async.

You'd have to do something like that:

function getInfo (cn) {
        return function(callback) {
            var anArray = [];
            redis_client.hgetall('chat_info:' + cn, function (err, vals) {
                if(err) { throw err; }
                for(i in vals) {
                        anArray.push(vals[i]);
                }
                return callback(anArray);
            });
        };
}

redis_client.hgetall('chat_rooms:' + POST.chat_name, function (err, val) {
        if(err) { throw err; }
        var     vars = [],
                rArr = [],
                callbacks = [];

        for (i in val) {
                vars.push(i);
        }

        for(var i = 0; i < vars.length; i += 1) {
                if(i%2 === 0) {
                        callbacks.push(getInfo(vars[i]));
                }
        }

        async.series(callbacks, function (err, results) {
           // Final code here
        });
});