Sí, las promesas son devoluciones de llamada asincrónicas. No pueden hacer nada que las devoluciones de llamada no puedan hacer, y usted enfrenta los mismos problemas con la asincronía que con las devoluciones de llamada simples.
Sin embargo, las promesas son más que simples devoluciones de llamada. Son una abstracción muy poderosa, permiten un código funcional más limpio y mejor con menos repeticiones propensas a errores.
Entonces, ¿cuál es la idea principal?
Las promesas son objetos que representan el resultado de un cálculo único (asíncrono). Ellos resuelven a ese resultado sólo una vez. Hay algunas cosas que significa esto:
Las promesas implementan un patrón de observación:
- No necesita conocer las devoluciones de llamada que utilizarán el valor antes de que se complete la tarea.
- En lugar de esperar devoluciones de llamada como argumentos de sus funciones, puede fácilmente
return
un objeto Promise
- La promesa almacenará el valor, y puede agregar de forma transparente una devolución de llamada cuando lo desee. Se llamará cuando el resultado esté disponible. La "transparencia" implica que cuando tienes una promesa y le agregas una devolución de llamada, no hace ninguna diferencia en tu código si el resultado ya ha llegado: la API y los contratos son los mismos, lo que simplifica mucho el almacenamiento en caché / memorización.
- Puede agregar múltiples devoluciones de llamada fácilmente
Las promesas son encadenables ( monádicas , si quieres ):
- Si necesita transformar el valor que representa una promesa, asigna una función de transformación sobre la promesa y obtiene una nueva promesa que representa el resultado transformado. No puede obtener sincrónicamente el valor para usarlo de alguna manera, pero puede levantar fácilmente la transformación en el contexto de la promesa. No hay devoluciones de llamada repetitivas.
- Si desea encadenar dos tareas asincrónicas, puede usar el
.then()
método. Se necesitará una devolución de llamada para ser llamada con el primer resultado, y devuelve una promesa para el resultado de la promesa de que la devolución de llamada regresa.
¿Suena complicado? Tiempo para un ejemplo de código.
var p1 = api1(); // returning a promise
var p3 = p1.then(function(api1Result) {
var p2 = api2(); // returning a promise
return p2; // The result of p2 …
}); // … becomes the result of p3
// So it does not make a difference whether you write
api1().then(function(api1Result) {
return api2().then(console.log)
})
// or the flattened version
api1().then(function(api1Result) {
return api2();
}).then(console.log)
El aplanamiento no viene mágicamente, pero puedes hacerlo fácilmente. Para su ejemplo muy anidado, el equivalente (cercano) sería
api1().then(api2).then(api3).then(/* do-work-callback */);
Si ver el código de estos métodos ayuda a comprender, aquí hay una promesa más básica en pocas líneas .
¿Cuál es el gran alboroto sobre las promesas?
La abstracción de Promise permite una mejor composibilidad de funciones. Por ejemplo, junto a then
encadenar, la all
función crea una promesa para el resultado combinado de múltiples promesas de espera paralela.
Por último, pero no menos importante, las promesas vienen con un manejo integrado de errores. El resultado del cálculo podría ser que la promesa se cumple con un valor o se rechaza con un motivo. Todas las funciones de composición manejan esto automáticamente y propagan errores en las cadenas de promesa, para que no tenga que preocuparse explícitamente en todas partes, en contraste con una implementación de devolución de llamada simple. Al final, puede agregar una devolución de llamada de error dedicada para todas las excepciones ocurridas.
Sin mencionar tener que convertir las cosas en promesas.
Eso es bastante trivial en realidad con buenas bibliotecas de promesa, vea ¿Cómo convierto una API de devolución de llamada existente en promesas?