JS Closures,Redis,loop,Async :: empty数组

时间:2013-06-16 07:54:56

标签: node.js loops asynchronous redis closures

我放弃了这一点。愿一些聪明的stackoverflow僧侣请修复我的错误吗?

代码是自我解释。客户端发送房间名称,服务器执行redis查找并将有效房间推送到阵列。添加所有房间后,应将列表发送给客户端。

问题是基于闭包,异步等。我理解这个问题,但无法获得解决方法,因为数组需要保留在函数内部。棘手。

代码:

function roomList(socket){

  var roomlist = [], rooms = getRooms(), p = /pChannel_/;

  redis.select(7, function(err,res){

    for (var k in rooms){

      if(rooms[k] != '' && p.test(rooms[k])){

        var key = 'channel:'+rooms[k];

        redis.hgetall(key, function (err, reply) { 

          if(reply){ 
            var c = io.sockets.manager.rooms[rooms[k]];
            roomlist.push( Array(reply['name'],c.length,reply['icon']) );
          }
          else { console.log('nothing found'); }

        });

      }

    }

    // here be dragons
    console.log(roomlist);
    socket.emit('roomList', roomlist);

  });

}

感谢。

3 个答案:

答案 0 :(得分:1)

看起来像async.map的作业:

function roomList(socket){
  var rooms = getRooms(), p = /pChannel_/;

  redis.select(7, function(err, res) {
    async.map(rooms, function(room, callback) {
      if (room === '' || ! p.test(room))
        return callback(null, null);

      var key = 'channel:' + room;
      var c   = io.sockets.manager.rooms[room];
      redis.hgetall(key, function (err, reply) {
        if (err)
          callback(err); // propagate Redis errors to final callback, don't know
                         // if you want that or not; use 'callback(null)' if not.
        else
        if (reply)
          callback(err, Array(reply.name, c.length, reply.icon) );
        else
          callback(err, null);
      });
    }, function(err, roomlist) {
      if (err)
         // handle Redis errors...

      // filter 'null' entries from roomlist
      roomlist = roomlist.filter(function(room) { return room !== null });
      console.log(roomlist);
      socket.emit('roomList', roomlist);
    });
  });
}

(未测试的)

答案 1 :(得分:0)

如果您只是想在发出响应之前等待房间列表完全构建(看起来非常合理),并且假设Q可用,那么您应该只需要一些额外的Q魔术线和一个闭包 - 在内部代码周围形成包装器,以保持对for循环的每次传递延迟的Q的可靠引用。

function roomList(socket) {
    redis.select(7, function(err, res) {
        var list = [],
            rooms = getRooms(),
            p = /pChannel_/,
            promises = [];
        for(var k in rooms) {
            if(rooms[k] != '' && p.test(rooms[k])) {
                (function(dfrd) {
                    promises.push(dfrd.promise);
                    var key = 'channel:' + rooms[k];
                    redis.hgetall(key, function(err, reply) {
                        if(reply) {
                            var c = io.sockets.manager.rooms[rooms[k]];
                            list.push( [reply['name'], c.length, reply['icon']] );
                        }
                        else {
                            console.log('nothing found');
                        }
                        dfrd.resolve();
                    });
                })(Q.defer());
            }
        }
        Q.all(promises).then(function() {
            console.log(list);
            socket.emit('roomList', list);
        });
    });
}

答案 2 :(得分:0)

好吧,伙计们。 OP明确表示她/他有兴趣了解事情应该如何运作。并且您不需要Q或async或任何其他第三方模块来实现此目的。

在初始代码中,有两个问题:

  • 使用Javascript,闭包范围是功能级别,而不是块级别。必须引入一个函数来定义一个合适的闭包。在这里,可以使用简单的forEach。

  • 在收到Redis的回复后,不会运行最后一步(即发出)。它必须在循环中调用。为了实现它,需要对项目进行计数,以便内部回调可以测试过程是否完成。

所以这是另一个版本:

function roomList(socket){

  var roomlist = [], rooms = getRooms(), p = /pChannel_/;

  redis.select(7, function(err,res){
    var count = rooms.length
    rooms.forEach( function(r) {
      if( r != '' && p.test(r) ) {
        var key = 'channel:'+r
        redis.hgetall(key, function (err, reply) { 
          if(reply) { 
            var c = io.sockets.manager.rooms[r];
            roomlist.push( Array(reply['name'],c.length,reply['icon']) );
          } else {
            console.log('nothing found');
          }
          if ( --count <= 0 ) {
            // here be dragons
            console.log(roomlist);
            socket.emit('roomList', roomlist);
          }
        });
      } else --count;
    });
  });
}