node.js redis异步查询

bzo*_*bzo 2 redis node.js

希望有人可以在node-redis上协助(简单)异步问题.我正在尝试从redis数据库中的哈希加载一个集合,然后再使用该填充集合.这是代码片段: -

var redis_client = redis.createClient(REDIS_PORT, REDIS_URL); 

redis_client.hgetall(target_hash,function(e,o){

    Object.keys(o).forEach(function(target){

        // get the "name" from the hash         
        redis_client.hget(o[target],"name",function(e,o){
        if (e){
                 console.log("Error occurred getting key: " + e);
              }
        else {
                 redis_client.sadd("newset",o);
             }
    });

});

// the following line prints nothing - why ?? 

redis_client.smembers("newset",redis.print);
Run Code Online (Sandbox Code Playgroud)

当我在redis中检查"newset"的内容时,它会按预期填充,但在运行时它显示为空.我确定这是一个异步问题 - 任何帮助非常感谢!

Gua*_*ang 7

hgetall是异步调用:当它从redis服务器收到回复时,它最终会调用你的回调function (target) { ... }.但是在你的脚本中,它实际上会立即返回.由于hgetall返回非常快,Node将立即运行下一个语句,smembers.但此时sadd语句还没有运行(即使你的系统非常快,因为还没有上下文切换).

您需要做的是确保smembers在sadd执行所有可能的调用之前未调用.redis_client提供的multi功能允许您排队所有sadd调用并在完成所有调用后运行回调.我没有测试过这段代码,但你可以试试这个:

var redis_client = redis.createClient(REDIS_PORT, REDIS_URL);

redis_client.hgetall(target_hash, function(e, o) {
  var multi = redis_client.multi();
  var keys = Object.keys(o);
  var i = 0;

  keys.forEach(function (target) {
    // get the "name" from the hash     
    redis_client.hget(o[target], "name", function(e, o) {
      i++;
      if (e) {
        console.log("Error occurred getting key: " + e);
      } else {
        multi.sadd("newset", o);
      }

      if (i == keys.length) {
        multi.exec(function (err, replies) {
          console.log("MULTI got " + replies.length + "replies");
          redis_client.smembers("newset", redis.print);
        });
      }
    });
  });
});
Run Code Online (Sandbox Code Playgroud)

有些库有一个内置的等价物forEach,允许你指定一个完成循环时要调用的函数.如果没有,你必须手动跟踪已经有多少回调,并smembers在最后一个回调后调用.