1

我放弃这个。可以请一些明智的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);

  });

}

谢谢。

4

3 回答 3

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

(未经测试)

于 2013-06-16T08:38:23.260 回答
0

来吧,伙计们。OP 明确表示她/他对了解事情应该如何工作感兴趣。而且您不需要 Q 或 async 或任何其他 3rd 方模块来实现这一点。

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

  • 使用 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;
    });
  });
}
于 2013-06-16T10:08:29.170 回答
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);
        });
    });
}
于 2013-06-16T09:36:43.793 回答