2012-04-18 101 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); 
       } 

     }});