2

誰かが node-redis に関する (単純な) 非同期の質問を手伝ってくれることを願っています。redis db のハッシュからセットをロードし、その設定されたセットをさらに使用しようとしています。コードスニペットは次のとおりです:-

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

redis で「newset」の内容を調べると、期待どおりに入力されていますが、実行時には空として表示されます。私はそれが非同期の問題だと確信しています - どんな助けも大歓迎です!

4

2 に答える 2

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

一部のライブラリにはforEach、ループがすべて完了したときに呼び出される関数を指定できる同等の機能が組み込まれています。そうでない場合は、コールバックの数を手動で追跡smembersし、最後のコールバックの後に呼び出す必要があります。

于 2012-04-18T14:21:26.273 に答える
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);
                 }

         }});
于 2012-10-30T19:53:50.200 に答える