¿Cuándo se considera .then(éxito, fracaso) un antipatrón para las promesas?
Eché un vistazo a las preguntas frecuentes sobre la promesa de bluebird , en las que se menciona que .then(success, fail)
es un antipatrón . No entiendo bien su explicación en cuanto a try
y catch
. ¿Qué hay de malo en lo siguiente?
some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
Parece que el ejemplo sugiere que la siguiente es la forma correcta.
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
¿Cual es la diferencia?
¿Cual es la diferencia?
La .then()
llamada devolverá una promesa que será rechazada en caso de que la devolución de llamada arroje un error. Esto significa que, cuando su éxito logger
falla, el error se pasará a la siguiente .catch()
devolución de llamada, pero no a la fail
devolución de llamada que va al lado success
.
Aquí hay un diagrama de flujo de control :
Para expresarlo en código síncrono:
// some_promise_call().then(logger.log, logger.log)
then: {
try {
var results = some_call();
} catch(e) {
logger.log(e);
break then;
} // else
logger.log(results);
}
El segundo log
(que es como el primer argumento de .then()
) solo se ejecutará en el caso de que no haya ocurrido ninguna excepción. El bloque etiquetado y la break
declaración se sienten un poco extraños, esto es en realidad para lo que sirve Pythontry-except-else
(¡lectura recomendada!).
// some_promise_call().then(logger.log).catch(logger.log)
try {
var results = some_call();
logger.log(results);
} catch(e) {
logger.log(e);
}
El catch
registrador también manejará excepciones de la llamada exitosa del registrador.
Hasta aquí la diferencia.
No entiendo muy bien su explicación en cuanto al intento de captura.
El argumento es que, por lo general, desea detectar errores en cada paso del procesamiento y que no debe usarlo en cadenas. La expectativa es que solo tenga un controlador final que maneje todos los errores, mientras que, cuando usa el "antipatrón", los errores en algunas de las devoluciones de llamada no se manejan.
Sin embargo, este patrón es realmente muy útil: cuando desea manejar errores que ocurrieron exactamente en este paso y desea hacer algo completamente diferente cuando no ocurrió ningún error, es decir, cuando el error es irrecuperable. Tenga en cuenta que esto está ramificando su flujo de control. Por supuesto, esto a veces es deseable.
¿Qué hay de malo en lo siguiente?
some_promise_call() .then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
Que tuviste que repetir tu devolución de llamada. prefieres querer
some_promise_call()
.catch(function(e) {
return e; // it's OK, we'll just log it
})
.done(function(res) {
logger.log(res);
});
También podrías considerar usarlo .finally()
para esto.
Los dos no son del todo idénticos. La diferencia es que el primer ejemplo no detectará una excepción lanzada en su success
controlador. Entonces, si su método solo debe devolver promesas resueltas, como suele ser el caso, necesita un catch
controlador final (u otro then
con un success
parámetro vacío). Claro, puede ser que su then
controlador no haga nada que pueda fallar, en cuyo caso usar un parámetro de 2 then
podría estar bien.
Pero creo que el punto del texto al que vinculaste es que then
es más útil que las devoluciones de llamada en su capacidad de encadenar un montón de pasos asincrónicos, y cuando realmente haces esto, la forma de 2 parámetros de then
sutilmente no se comporta como se esperaba. , por el motivo anterior. Es particularmente contradictorio cuando se usa en la mitad de la cadena.
Como alguien que ha hecho muchas cosas asincrónicas complejas y se ha topado con rincones como este más de lo que me gustaría admitir, realmente recomiendo evitar este antipatrón y optar por el enfoque de controlador separado.