Pergunta

Sou novo em JavaScript e ainda não estou familiarizado com funções assíncronas...

Estou trabalhando com node.js para criar um servidor de chat, isso é uma parte do meu código que está escutando getListConnected evento e quando foi acionado procure por todos conectados clients em um determinado namespace e, para cada cliente, armazeno seu 'nome de usuário' em outro array, converto-o em resposta json e envio:

socket.on('getListConnected', function(msg){
                        var clients = namespace.clients();//get all client in that nsp
                        var usernames = Array() ;//init array

                        for(i in clients)//for each clients
                        {
                           clients[i].get("username", function(value){
                               usernames.push(value);
                            });
                        }
                       socket.emit('getListConnected',JSON.stringify(usernames));//send
                    });

O problema com este código é que o método client.get() é assíncrono, o que significa que os nomes de usuário são enviados vazios.

Como posso esperar pelos nomes de usuário até que sejam preenchidos ou como posso esperar pelo loop até que termine?

Foi útil?

Solução

Você poderia usar middleware para promessas, algo como pássaro azul, ou você pode manter um contador para verificar se todos os nomes de usuário foram obtidos, algo como

socket.on('getListConnected', function (msg) {
    var clients   = namespace.clients();
    var usernames =  [];
    var counter1  =  0;
    var counter2  =  0;

    for (i in clients) {

        counter1++; // number of clients

        clients[i].get("username", function (value) {
            usernames.push(value);
            counter2++; // number of clients added to array

            if (counter1 === counter2) {
                socket.emit('getListConnected', JSON.stringify(usernames));
            }

        });
    }

});

Outras dicas

Aqui está um exemplo do Bluebird, personalizado para sua situação:[ele toma emprestado pesadamente de Exemplo de Victor Quinn]

Usando a mesma definição de Promessa que Victor usou:

var Promise = require('bluebird');

var promiseWhile = function(condition, action) {
    var resolver = Promise.defer();

    var loop = function() {
        if (!condition()) return resolver.resolve();
        return Promise.cast(action())
            .then(loop)
            .catch(resolver.reject);
    };

    process.nextTick(loop);

    return resolver.promise;
};

Instanciado com sua chamada personalizada:

var i = 0;
promiseWhile(function() {
    return i < clients.length;
}, function(value) {
    return new Promise(function(resolve, reject) {
        clients[i].get("username", function(value){
                                       usernames.push(value);
            });
            i++;
            resolve();
    });
}).then(function() {
    console.log("usernames are: " + usernames);
});
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top