¿Cómo puedo esperar eventos asincrónicos en Javascript?
-
20-12-2019 - |
Pregunta
Soy nuevo en JavaScript y todavía no estoy familiarizado con las funciones asincrónicas...
Estoy trabajando con node.js para crear un servidor de chat, esta es una parte de mi código que escucha getListConnected
evento y cuando se activó buscar todos los conectados clients
en un espacio de nombres determinado, y luego, para cada cliente, almaceno su 'nombre de usuario' en otra matriz, lo convierto en respuesta json y luego envío:
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
});
El problema con este código es que el método client.get() es asincrónico, lo que significa que los nombres de usuario se envían vacíos.
¿Cómo puedo esperar los nombres de usuario hasta que se completen o cómo puedo esperar el ciclo hasta que finalice?
Solución
Podrías usar middleware para promesas, algo como Azulejo, o puede mantener un contador para verificar si se han obtenido todos los nombres de usuario, 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));
}
});
}
});
Otros consejos
Aquí hay un ejemplo de Bluebird, personalizado para su situación:[toma prestado mucho de El ejemplo de Víctor Quinn]
Usando la misma definición de Promesa que usó Víctor:
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 con su llamada 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);
});