node.js - side - node server start
Flujo de control Node.js: devoluciones de llamada o promesas? (3)
He estado experimentando con un enfoque declarativo con esta biblioteca: http://chainsjs.org aún queda mucho por hacer, pero le da la posibilidad de definir un "mapa de ejecución" donde puede controlar completamente el flujo. de ejecución desde un mapeo simple.
Sé que hay muchas bibliotecas de flujo de control para node.js. Algunos de ellos permiten que una cadena async funcione con devoluciones de llamada (como async, asyncblock, etc.), los otros usan el concepto de promesa (Q, diferido, futuros, etc.). Dado que un script de larga ejecución realiza una serie de acciones una tras otra que pueden fallar en cualquier momento, ¿qué flujo de control preferiría y por qué? ¿Cuáles son los pros y los contras?
No creo que haya muchos pros y contras objetivos. Async es muy popular (basado en paquetes npm que dependen de él ).
Me gustan las bibliotecas de flujo de control (específicamente asíncronas), porque me resulta más fácil de entender. Las promesas me confunden, mientras que async es fácilmente comprensible. Sin embargo, sospecho que es solo una curva de aprendizaje, y las promesas serían más legibles si me esforzara en aprenderlas. ¿Pero debo esperar que la gente también intente leer mi código?
También hay un tercer tipo - Fibers . Las fibras todavía no funcionan en Windows, pero (IMO) ofrece la sintaxis más clara para las cosas que deben ejecutarse en serie.
Pros para devoluciones de llamada:
- Simple de entender y crear.
- Algo más eficiente , porque se crean menos objetos y se recolecta basura.
- El nodo optó por devoluciones de llamada
(error,result)
largo. Recomiendo seguir su orden de argumentos para la consistencia. (A diferencia de decir(result1, result2, result3, error)
.)
Pros para las promesas:
- Proporciona una interfaz fluida , que a veces puede ayudar a mitigar el infierno de devolución de llamadas anidadas, como se muestra aquí . El código parece fluir linealmente encadenando
.then(foo).then(bar)
llamadas. - Una biblioteca de buenas promesas le permitirá ejecutar muchas operaciones asíncronas en paralelo y continuar solo cuando se hayan completado. La biblioteca Deferred hace a la perfección a través del
map
, Q haallResolved
y ES6 Promises ofrecePromise.all()
. (Esto también es posible con devoluciones de llamada, por ejemplo, usandoasync.parallel()
, pero no integrado). - Una biblioteca de buenas promesas le permitirá especificar una función de manejo de errores que se llamará si falla alguna de las funciones en cola. Para hacer esto con las devoluciones de llamada se requiere un poco de repetición:
if (err) return callback(err);
al comienzo de cada devolución de llamada.
Tendría sentido utilizar devoluciones de llamada cerca de la parte inferior de la pila , para el código que se ejecutará muchas veces por segundo. Más arriba en la pila, las promesas pueden ser preferibles, ya que son más fáciles de leer y entender, y pueden manejar los errores con más elegancia.
Vale la pena señalar que las promesas se pueden construir a partir de devoluciones de llamada en tiempo de ejecución. Por lo tanto, puede implementar su código central en el formulario de devolución de llamada minimalista y aún así exponer una versión de la biblioteca de promesas si así lo desea. (Como en Q.nfbind()
.)
Me interesaría escuchar otros pros / contras.
Consejo extra: ¡ Siempre maneje los errores! Con ambos métodos, si no maneja el error, simplemente desaparecerá, dejándole en la oscuridad sobre por qué su código no funcionó como se esperaba.
Las devoluciones de llamada siempre deben controlarse
if (err) ...
y las promesas siempre deben tener un.catch()
si no se devuelven.Incluso si espera errores de vez en cuando, y no necesita manejarlos, no manejar errores inesperados significa que no escuchará los errores de los desarrolladores, como errores tipográficos, si el código se modifica en el futuro.
Una alternativa a
.catch()
para Promises es escuchar los rechazos no manejados . ¡Personalmente lo uso para emitir una advertencia de que.catch()
!