【问题标题】:NodeJS + redis gives weird resultsNodeJS + redis 给出了奇怪的结果
【发布时间】:2013-12-14 15:57:31
【问题描述】:

也许结果并不奇怪,但我在 1-2 个月前开始使用 Node,所以对我来说它们是……

我有一个循环,它对hgetall(Redis 命令)返回的数组的所有其他值进行排序,在该循环中,我调用一个函数从另一个表中获取所有值,其中键存储在排序后的数组中。这比我想象的更难以解释。这是我的代码:

Pastebin:http://pastebin.com/tAVhSUV1(或见下文)

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);
                        });
                }
        }      
});

getInfo() 的调用的回调在整个循环之后执行。我在这里错过了什么吗?因为它做不到,对吧? (当我使用 rArr(在循环之后)它是空的,nb但是如果我将它记录在回调中,它会在其他所有内容之后被记录循环之后)

【问题讨论】:

    标签: node.js node-redis


    【解决方案1】:

    是的,这可能是正常的。

    了解回调是在hgetall 调用之后执行的。这意味着当 redis 函数收到一些消息时,它将调用回调。也就是说,所有的回调都可以在以后执行。

    由于 javascript 只在一个线程中工作,对 hgetall 的调用应该被阻塞以在它们进入 for 循环时被执行。但是因为您更肯定使用异步 IO。 for 循环结束,然后它将开始调用在 javascript 事件循环中排队的每个回调。

    编辑

    不幸的是,要实现您想要做的事情,您应该将代码包装在许多其他回调中。你可以使用这个项目让它变得更简单:https://github.com/caolan/async

    您应该可以使用npm install async 安装它。

    你必须这样做:

    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
            });
    });
    

    【讨论】:

    • 我该怎么做才能使 hgetall 阻塞呢?不要以为redis支持同步调用,我也想不通怎么改写成我想要的样子。
    • 不要让它同步,它会阻塞服务器的所有其他请求。而是使用类似 asyncjs 的东西。
    • 感谢您的回答,让我对此事有所了解。我想我会用笔和一些纸坐下来重新考虑一下。
    • 好吧,别担心,如果还不算太晚,你可以试试 python 和 gevent/gunicorn。使用可用的框架之一,您应该能够使用 async/io 编写没有回调的代码,这应该会产生与 node.js 一样好的性能。也不要担心回调的混乱,你不是发布设计糟糕的东西的人。
    猜你喜欢
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    • 2019-08-23
    相关资源
    最近更新 更多