2

希望有人可以帮助解决关于 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);

当我检查 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

除非您确实需要交易,否则不应使用 multi 。

只需保留交易计数器并在最终回调中调用 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 回答