JS闭包,Redis,循环,asynchronous::空数组

我放弃了这一点。 可能一些明智的stackoverflow僧侣请修复我的错误?

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

问题是closures,asynchronous等基础。 我理解这个问题,但不能得到解决方法,因为数组需要保留在函数内。 棘手。

码:

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

谢谢。

来吧,伙计们。 OP通过理解事情应该如何工作明确地表示她/他感兴趣。 而且你不需要Q或asynchronous或任何其他第三方模块来实现这一点。

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

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

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

所以这里是另一个版本:

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

看起来像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); }); }); } 

(另)

如果你只是想在发布响应之前等待完整的房间列表(看起来非常合理),并假设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); }); }); }