1

私はこれをあきらめます。賢明なスタックオーバーフロー修道士の何人かが私のバグを修正してくれませんか?

コードは自明です。クライアントはルーム名を送信し、サーバーは 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

0

さあ、皆さん。OPは、物事がどのように機能するかを理解することに興味があると明示的に述べました。また、これを実装するために Q や async、その他のサードパーティ モジュールは必要ありません。

最初のコードには、次の 2 つの問題があります。

  • 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 に答える