javascript - promises - Controle el problema de flujo con node/redis y callbacks?
object promise node js (3)
¿Podría pedir algún consejo sobre un problema de flujo de control con nodo y redis? (también conocido como codificador de Python tratando de acostumbrarse a JavaScript)
No entiendo por qué client.smembers
y client.get
(búsquedas de Redis) deben ser devoluciones de llamada en lugar de simplemente declaraciones, hace la vida muy complicada.
Básicamente, me gustaría consultar un conjunto, y luego, cuando tenga los resultados para el conjunto, necesito realizar un get para cada resultado. Cuando tenga todos los datos , necesito transmitirlos nuevamente al cliente.
Actualmente hago esto dentro de dos devoluciones de llamada, usando un objeto global, que parece desordenado. Ni siquiera estoy seguro de si es seguro (¿esperará el código a que un client.get
complete antes de comenzar otro?).
El código actual se ve así:
var all_users = [];
// Get all the users for this page.
client.smembers("page:" + current_page_id, function (err, user_ids ) {
// Now get the name of each of those users.
for (var i = 0; i < user_ids.length; i++) {
client.get(''user:'' + user_ids[i] + '':name'', function(err, name) {
var myobj = {};
myobj[user_ids[i]] = name;
all_users.push(myobj);
// Broadcast when we have got to the end of the loop,
// so all users have been added to the list -
// is this the best way? It seems messy.
if (i === (user_ids.length - 1)) {
socket.broadcast(''all_users'', all_users);
}
});
}
});
Pero esto parece muy complicado. ¿Es realmente la mejor manera de hacer esto? ¿Cómo puedo estar seguro de que todas las búsquedas se han realizado antes de llamar a socket.broadcast
?
rasca la cabeza Gracias de antemano por cualquier consejo.
No entiendo por qué
client.smembers
yclient.get
(búsquedas de Redis) deben ser devoluciones de llamada en lugar de simplemente declaraciones, hace la vida muy complicada.
Eso es lo que es Node. (Estoy bastante seguro de que este tema se debatió más que suficientes veces aquí, analizo otras preguntas, definitivamente está ahí)
¿Cómo puedo estar seguro de que todas las búsquedas se han realizado antes de llamar a
socket.broadcast
?
Eso es lo que se err
en la función de devolución de llamada. Esto es un poco el estándar de Node: el primer parámetro en la devolución de llamada es el objeto de error ( null
si todo está bien). Entonces use algo como esto para asegurarse de que no haya errores:
if (err) {
... // handle errors.
return // or not, it depends.
}
... // process results
Pero esto parece muy complicado.
Te acostumbrarás. De hecho, me resulta agradable, cuando el código está bien formateado y el proyecto está inteligentemente estructurado.
Otras formas son:
Si no le gusta mucho escribir material de devolución de llamada, es posible que desee probar con streamlinejs :
var all_users = [];
// Get all the users for this page.
var user_ids = client.smembers("page:" + current_page_id, _);
// Now get the name of each of those users.
for (var i = 0; i < user_ids.length; i++) {
var name = client.get(''user:'' + user_ids[i] + '':name'', _);
var myobj = {};
myobj[user_ids[i]] = name;
all_users.push(myobj);
}
socket.broadcast(''all_users'', all_users);
Tenga en cuenta que una desventaja de esta variante es que solo se buscará un nombre de usuario a la vez. Además, aún debes estar al tanto de lo que este código realmente hace.
Async es una gran biblioteca y deberías echarle un vistazo. Por qué ? Código / proceso limpio / fácil de rastrear ... etc.
Además, tenga en cuenta que toda su función asíncrona se procesará después de su ciclo for. En su ejemplo, puede resultar en un valor "i" incorrecto. Use cierre:
for (var i = 0; i < user_ids.length; i++) { (function(i) {
client.get(''user:'' + user_ids[i] + '':name'', function(err, name) {
var myobj = {};
myobj[user_ids[i]] = name;
all_users.push(myobj);
// Broadcast when we have got to the end of the loop,
// so all users have been added to the list -
// is this the best way? It seems messy.
if (i === (user_ids.length - 1)) {
socket.broadcast(''all_users'', all_users);
}
});
})(i)}
Lo que debes hacer para saber cuándo está terminado es usar un patrón recursivo como asincrónico (creo). Es mucho más sencillo que hacerlo tú mismo.
async.series({
getMembers: function(callback) {
client.smembers("page:" + current_page_id, callback);
}
}, function(err, results) {
var all_users = [];
async.forEachSeries(results.getMembers, function(item, cb) {
all_users.push(item);
cb();
}, function(err) {
socket.broadcast(''all_users'', all_users);
});
});
Es posible que este código no sea válido, pero debería poder averiguar cómo hacerlo.
La biblioteca Step también es buena (y creo que solo 30 ~ línea de código)