promesas - ¿Cómo optimizar este código de Node.js+q para evitar el infierno de devolución de llamada?
q defer() node js (3)
Sí, una forma de limpiarlo sería definir una función con nombre:
function SuccessfulSend(result) {
if (result == constants.EVENT_EMIT_SENT) {
appLog.debug("Message [%s] sent!!!", msg._id);
messageService.remove(msg._id)
.then(function(result) {
appLog.debug("Message deleted: [%s]", msg._id);
})
.fail(function(err) {
appLog.error("The message couldn''t be deleted: [%s]", msg._id);
});
}else if (result == constants.EVENT_EMIT_NOT_SENT_AND_NOT_STORED) {
appLog.debug("Message [%s] not sent", msg._id);
}
}
y entonces:
.then(SuccessfulSend);
Estoy usando Q para prevenir el infierno de devolución de llamada, pero he llegado a una parte de mi código que no sé cómo organizar:
Estoy buscando mensajes programados para ser entregados. Para cada uno de ellos, trato de enviarlos uno por uno y si se pueden enviar, los quita de la base de datos. La parte fea es tener un then () dentro de un ciclo for . ¡De esta forma termino anidando promesas en lugar de callbacks anidados! Sugerencias?
appLog.debug("Looking for scheduled messages");
var messages = messageService.findScheduled()
.then(function(messages){
appLog.debug("found [%d] stored messages",messages.length);
for(var i = 0; i<messages.length; i++){
messageService.send(msg.namespace, msg.message, msg.data)
.then(function(result) {
if (result == constants.EVENT_EMIT_SENT) {
appLog.debug("Message [%s] sent!!!", msg._id);
messageService.remove(msg._id)
.then(function(result) {
appLog.debug("Message deleted: [%s]", msg._id);
})
.fail(function(err) {
appLog.error("The message couldn''t be deleted: [%s]", msg._id);
});
}else if (result == constants.EVENT_EMIT_NOT_SENT_AND_NOT_STORED) {
appLog.debug("Message [%s] not sent", msg._id);
}
});
}
});
Simplemente refactorizar sus funciones en funciones nombradas y tratar de hacer un mejor uso del encadenamiento prometedor sería una gran mejora.
var messageService, appLog, constants;
appLog.debug("Looking for scheduled messages");
messageService.findScheduled()
.then(function(messages){
appLog.debug("found [%d] stored messages", messages.length);
messages.map(processMessage);
});
function processMessage(msg) {
msg.data.dontStore = true;
messageService
.send(msg.namespace, msg.message, msg.data)
.then(function(result) {
if (result !== constants.EVENT_EMIT_SENT) {
throw new Error(constants.EVENT_EMIT_SENT);
}
appLog.debug("Message [%s] sent!!!", msg._id);
return removeMessage(msg);
})
.fail(function(err) {
appLog.debug("Message [%s] not sent", msg._id);
throw err;
});
}
function removeMessage(msg) {
return messageService.remove(msg._id)
.then(function() {
appLog.message("Message deleted: [%s]", msg._id);
})
.fail(function(err) {
appLog.message("The message couldn''t be deleted: [%s]", msg._id);
throw err;
});
}
La parte fea es tener un then () dentro de un bucle for
No, eso puede suceder. Aunque el estilo de programación funcional de las promesas generalmente lleva a utilizar .map()
con una devolución de llamada de todos modos :-) La bucle es una estructura de control y requiere anidamiento (excepto que se usan excepciones para el flujo de control , es decir, bifurcación). Sin embargo, lo que no tienes que hacer es anidar promesas en callbacks de promesas.
Simplificaría tu cuerpo de bucle para
function sendAndDelete(msg) {
return messageService.send(msg.namespace, msg.message, msg.data)
.then(function(result) {
if (result == constants.EVENT_EMIT_SENT) {
appLog.debug("Message [%s] sent!!!", msg._id);
return msg._id;
} else if (result == constants.EVENT_EMIT_NOT_SENT_AND_NOT_STORED) {
appLog.debug("Message [%s] not sent", msg._id);
throw new Error("Message not sent");
}
})
.then(messageService.remove)
.then(function(result) {
appLog.debug("Message deleted: [%s]", msg._id);
}, function(err) {
appLog.error("The message has not been deleted: [%s]", msg._id);
});
}
Ahora puedes hacer algo como
messageService.findScheduled()
.then(function(messages){
appLog.debug("found [%d] stored messages",messages.length);
return Q.all(messages.map(sendAndDelete));
})
.then(function() {
appLog.debug("all messages done");
});