2012-04-18 69 views
2

希望有人可以协助node-redis上的(简单)异步问题。我试图从redis db中的一个散列加载一个集合,然后再使用这个集合集合。下面的代码片段: -node.js 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); 

当我审视“newset”的预期被填充Redis的内容,但在运行时,它显示为空。我确定这是一个异步问题 - 任何帮助非常感谢!

+3

一个幽默的比喻与异步问题的时候,这将有助于你 - https://groups.google.com/forum/ #!MSG /谷歌的Web的工具包/ -soVdfMGug8/vRmqIcAZ5zsJ – 2012-04-18 14:47:02

回答

7

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

您需要做的是在所有可能的sadd调用执行之前确保不要调用smembers。 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); 
     }); 
     } 
    }); 
    }); 
}); 

一些图书馆的forEach内置等价,使您可以指定一种功能,当循环全部完成被调用。如果没有,您必须手动跟踪有多少次回调,并在最后一次回拨后致电smembers

1

除非实际需要交易,否则不应使用多项。

只要保持交易的柜台和调用smembers最终回调

var redis_client = redis.createClient(REDIS_PORT, REDIS_URL); 
var keys = Object.keys(o); 
var i = 0; 
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){ 
     i++ 
     if (e){ 
       console.log("Error occurred getting key: " + e); 
       } 
     else { 
       redis_client.sadd("newset",o); 
       if (i == keys.length) { 
        redis_client.smembers("newset", redis.print); 
       } 

     }});