¿No son las promesas solo devoluciones de llamada?

447
Benjamin Gruenbaum 2014-03-21 06:49.

He estado desarrollando JavaScript durante algunos años y no entiendo en absoluto el alboroto por las promesas.

Parece que todo lo que hago es cambiar:

api(function(result){
    api2(function(result2){
        api3(function(result3){
             // do work
        });
    });
});

Para lo cual podría usar una biblioteca como async de todos modos, con algo como:

api().then(function(result){
     api2().then(function(result2){
          api3().then(function(result3){
               // do work
          });
     });
});

Cuál es más código y menos legible. No gané nada aquí, tampoco es mágicamente 'plano' de repente. Por no hablar de tener que convertir las cosas en promesas.

Entonces, ¿cuál es el gran alboroto sobre las promesas aquí?

10 answers

647
Oscar Paz 2014-03-21 07:07.

Las promesas no son devoluciones de llamada. Una promesa representa el resultado futuro de una operación asincrónica . Por supuesto, si los escribe de la manera que lo hace, obtiene pocos beneficios. Pero si los escribe de la forma en que deben usarse, puede escribir código asincrónico de una manera que se asemeje al código sincrónico y sea mucho más fácil de seguir:

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
});

Ciertamente, no mucho menos código, pero sí mucho más legible.

Pero, este no es el final. Descubramos los verdaderos beneficios: ¿Qué pasaría si quisiera verificar si hay algún error en cualquiera de los pasos? Sería un infierno hacerlo con devoluciones de llamada, pero con promesas, es pan comido:

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
}).catch(function(error) {
     //handle any error that may occur before this point
});

Casi lo mismo que un try { ... } catchbloque.

Aun mejor:

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
}).catch(function(error) {
     //handle any error that may occur before this point
}).then(function() {
     //do something whether there was an error or not
     //like hiding an spinner if you were performing an AJAX request.
});

Y aún mejor: ¿Qué pasa si esas llamadas a 3 api, api2, api3podían ejecutar de forma simultánea (por ejemplo, si fueran llamadas AJAX) pero necesitan que esperar a los tres? Sin promesas, debería tener que crear algún tipo de contador. Con promesas, usar la notación ES6 es otro pedazo de pastel y bastante bueno:

Promise.all([api(), api2(), api3()]).then(function(result) {
    //do work. result is an array contains the values of the three fulfilled promises.
}).catch(function(error) {
    //handle the error. At least one of the promises rejected.
});

Espero que veas Promises bajo una nueva luz ahora.

176
Bergi 2014-03-22 04:50.

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 devoluciones de llamada. Son una abstracción muy poderosa, permiten un código más limpio y mejor, funcional con un texto repetitivo menos propenso a errores.

Entonces, ¿cuál es la idea principal?

Las promesas son objetos que representan el resultado de un único cálculo (asincrónico). Ellos resuelven a ese resultado sólo una vez. Hay algunas cosas que significa esto:

Las promesas implementan un patrón de observador:

  • No es necesario que conozca 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 para sus funciones, puede fácilmente returnun objeto Promise
  • La promesa almacenará el valor y puede agregar una devolución de llamada de forma transparente 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 importa si el resultado ha llegado ya a tu código: 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. Sin devoluciones de llamada estándar.
  • Si desea encadenar dos tareas asincrónicas, puede usar el .then()método. Se necesitará una devolución de llamada para que se llame con el primer resultado y devuelve una promesa para el resultado de la promesa de que la devolución de llamada devuelve.

¿Suena complicado? Es hora de 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 por arte de magia, pero puedes hacerlo fácilmente. Para su ejemplo fuertemente 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 biblioteca de promesas más básica en unas pocas líneas .

¿Cuál es el gran alboroto sobre las promesas?

La abstracción Promise permite una mejor componibilidad de funciones. Por ejemplo, junto a thenpara encadenamiento, la allfunción crea una promesa para el resultado combinado de múltiples promesas de espera en paralelo.

Por último, pero no menos importante, las promesas vienen con un manejo de errores integrado. El resultado del cálculo podría ser que la promesa se cumple con un valor o se rechaza con una razón. Todas las funciones de composición manejan esto automáticamente y propagan errores en las cadenas de promesas, por lo que no necesita preocuparse explícitamente por todas partes, a diferencia de 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.

Por no hablar de tener que convertir las cosas en promesas.

En realidad, eso es bastante trivial con las bibliotecas de buenas promesas, consulte ¿Cómo convierto una API de devolución de llamada existente en promesas?

23
John Weisz 2016-09-13 10:25.

Además de las respuestas ya establecidas, con funciones ES6 flecha promesas de convertir una pequeña enana azul brillante modestamente recta en una gigante roja. Eso está a punto de colapsar en una supernova:

api().then(result => api2()).then(result2 => api3()).then(result3 => console.log(result3))

Como señaló oligofren , sin argumentos entre las llamadas a la API, no necesita las funciones de contenedor anónimas en absoluto:

api().then(api2).then(api3).then(r3 => console.log(r3))

Y finalmente, si quieres alcanzar un nivel de agujero negro supermasivo, puedes esperar promesas:

async function callApis() {
    let api1Result = await api();
    let api2Result = await api2(api1Result);
    let api3Result = await api3(api2Result);

    return api3Result;
}
16
dww 2018-04-18 22:28.

Además de las impresionantes respuestas anteriores, se pueden agregar 2 puntos más:

1. Diferencia semántica:

Las promesas pueden estar ya resueltas en el momento de la creación. Esto significa que garantizan condiciones más que eventos . Si ya están resueltos, la función resuelta que se le ha pasado todavía se llama.

Por el contrario, las devoluciones de llamada manejan eventos. Por lo tanto, si el evento que le interesa ocurrió antes de que se registrara la devolución de llamada, no se llama a la devolución de llamada.

2. Inversión de control

Las devoluciones de llamada implican la inversión de control. Cuando registra una función de devolución de llamada con cualquier API, el tiempo de ejecución de Javascript almacena la función de devolución de llamada y la llama desde el bucle de eventos una vez que está lista para ejecutarse.

Consulte El bucle de eventos de Javascript para obtener una explicación.

Con Promises , el control reside en el programa de llamadas. El método .then () se puede llamar en cualquier momento si almacenamos el objeto de promesa.

13
Duncan Luk 2017-07-24 03:24.

Además de las otras respuestas, la sintaxis de ES2015 se combina a la perfección con las promesas, lo que reduce aún más el código estándar:

// Sequentially:
api1()
  .then(r1 => api2(r1))
  .then(r2 => api3(r2))
  .then(r3 => {
      // Done
  });

// Parallel:
Promise.all([
    api1(),
    api2(),
    api3()
]).then(([r1, r2, r3]) => {
    // Done
});
6
Ayush Jain 2019-03-06 21:40.

No, en absoluto.

Las devoluciones de llamada son simplemente funciones en JavaScript que deben llamarse y luego ejecutarse después de que la ejecución de otra función haya finalizado. Entonces, ¿cómo sucede?

En realidad, en JavaScript, las funciones se consideran en sí mismas como objetos y, por lo tanto, como todos los demás objetos, incluso las funciones pueden enviarse como argumentos a otras funciones . El caso de uso más común y genérico que se puede pensar es la función setTimeout () en JavaScript.

Las promesas no son más que un enfoque mucho más improvisado de manejo y estructuración de código asincrónico en comparación con hacer lo mismo con las devoluciones de llamada.

La promesa recibe dos devoluciones de llamada en la función constructora: resolver y rechazar. Estas devoluciones de llamada internas nos brindan un control detallado sobre el manejo de errores y los casos de éxito. La devolución de llamada de resolución se usa cuando la ejecución de la promesa se realizó correctamente y la devolución de llamada de rechazo se usa para manejar los casos de error.

5
Kjell Schubert 2014-04-02 04:09.

Las promesas no son devoluciones de llamada, ambos son modismos de programación que facilitan la programación asincrónica. El uso de un estilo de programación asíncrono / en espera usando corrutinas o generadores que devuelven promesas podría considerarse un tercer idioma de este tipo. Una comparación de estos modismos en diferentes lenguajes de programación (incluido Javascript) está aquí: https://github.com/KjellSchubert/promise-future-task

2
Apoorv 2016-06-21 03:42.

Ninguna promesa es simplemente envoltorio en devoluciones de llamada

ejemplo Puede usar promesas nativas de JavaScript con node js

my cloud 9 code link : https://ide.c9.io/adx2803/native-promises-in-node

/**
* Created by dixit-lab on 20/6/16.
*/

var express = require('express');
var request = require('request');   //Simplified HTTP request client.


var app = express();

function promisify(url) {
    return new Promise(function (resolve, reject) {
    request.get(url, function (error, response, body) {
    if (!error && response.statusCode == 200) {
        resolve(body);
    }
    else {
        reject(error);
    }
    })
    });
}

//get all the albums of a user who have posted post 100
app.get('/listAlbums', function (req, res) {
//get the post with post id 100
promisify('http://jsonplaceholder.typicode.com/posts/100').then(function (result) {
var obj = JSON.parse(result);
return promisify('http://jsonplaceholder.typicode.com/users/' + obj.userId + '/albums')
})
.catch(function (e) {
    console.log(e);
})
.then(function (result) {
    res.end(result);
}
)

})


var server = app.listen(8081, function () {

var host = server.address().address
var port = server.address().port

console.log("Example app listening at http://%s:%s", host, port)

})


//run webservice on browser : http://localhost:8081/listAlbums
1
Hamid Shoja 2019-12-20 21:49.

Las Promesas de JavaScript en realidad usan funciones de devolución de llamada para determinar qué hacer después de que una Promesa se haya resuelto o rechazado, por lo tanto, ambas no son fundamentalmente diferentes. La idea principal detrás de Promises es recibir devoluciones de llamada, especialmente devoluciones de llamada anidadas donde desea realizar una especie de acciones, pero sería más legible.

0
Willem van der Veen 2020-05-06 23:03.

Resumen de promesas:

En JS podemos envolver operaciones asincrónicas (por ejemplo, llamadas a bases de datos, llamadas AJAX) en promesas. Por lo general, queremos ejecutar alguna lógica adicional en los datos recuperados. Las promesas de JS tienen funciones de controlador que procesan el resultado de las operaciones asincrónicas. Las funciones del controlador pueden incluso tener otras operaciones asincrónicas dentro de ellas que podrían depender del valor de las operaciones asincrónicas anteriores.

Una promesa siempre tiene de los 3 estados siguientes:

  1. pendiente: estado inicial de toda promesa, ni cumplida ni rechazada.
  2. cumplido: La operación se completó con éxito.
  3. rechazado: la operación falló.

Una promesa pendiente se puede resolver / cumplir o rechazar con un valor. Luego, se llaman los siguientes métodos de controlador que toman devoluciones de llamada como argumentos:

  1. Promise.prototype.then() : Cuando se resuelva la promesa, se llamará al argumento de devolución de llamada de esta función.
  2. Promise.prototype.catch() : Cuando se rechaza la promesa, se llamará al argumento de devolución de llamada de esta función.

Aunque la habilidad de los métodos anteriores obtiene argumentos de devolución de llamada, son muy superiores a usar solo devoluciones de llamada, aquí hay un ejemplo que aclarará mucho:

Ejemplo

function createProm(resolveVal, rejectVal) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() > 0.5) {
                console.log("Resolved");
                resolve(resolveVal);
            } else {
                console.log("Rejected");
                reject(rejectVal);
            }
        }, 1000);
    });
}

createProm(1, 2)
    .then((resVal) => {
        console.log(resVal);
        return resVal + 1;
    })
    .then((resVal) => {
        console.log(resVal);
        return resVal + 2;
    })
    .catch((rejectVal) => {
        console.log(rejectVal);
        return rejectVal + 1;
    })
    .then((resVal) => {
        console.log(resVal);
    })
    .finally(() => {
        console.log("Promise done");
    });

  • La función createProm crea promesas que se resuelven o rechazan basándose en un Nr aleatorio después de 1 segundo
  • Si la promesa se resuelve then, se llama al primer método y el valor resuelto se pasa como argumento de la devolución de llamada.
  • Si se rechaza la promesa, se llama al primer catchmétodo y el valor rechazado se pasa como argumento
  • Los métodos catchy thendevuelven promesas, por eso podemos encadenarlos. Envuelven cualquier valor devuelto Promise.resolvey cualquier valor arrojado (utilizando la throwpalabra clave) Promise.reject. Entonces, cualquier valor devuelto se transforma en una promesa y en esta promesa podemos volver a llamar a una función de controlador.
  • Las cadenas de promesas nos brindan un control más preciso y una mejor descripción general que las devoluciones de llamada anidadas. Por ejemplo, el catchmétodo maneja todos los errores que han ocurrido antes que el catchcontrolador.

Related questions

MORE COOL STUFF

La estrella de HGTV, Christina Hall, revela que tiene 'envenenamiento por mercurio y plomo' probablemente por voltear 'casas asquerosas'

La estrella de HGTV, Christina Hall, revela que tiene 'envenenamiento por mercurio y plomo' probablemente por voltear 'casas asquerosas'

La estrella de HGTV, Christina Hall, revela que le diagnosticaron envenenamiento por mercurio y plomo, probablemente debido a su trabajo como manipuladora de casas.

La estrella de 'Love Is Blind' Brennon Lemieux responde a los cargos de violencia doméstica

La estrella de 'Love Is Blind' Brennon Lemieux responde a los cargos de violencia doméstica

Recientemente salió a la luz un informe policial que acusa a la estrella de 'Love Is Blind', Brennon, de violencia doméstica. Ahora, Brennon ha respondido a los reclamos.

Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia Judd en un momento festivo de pánico

Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia Judd en un momento festivo de pánico

Conozca cómo Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia mientras organizaba la primera celebración de Acción de Gracias desde que murió su madre, Naomi Judd.

Experto en lenguaje corporal explica los 'paralelos' entre Kate Middleton y la princesa Diana

Experto en lenguaje corporal explica los 'paralelos' entre Kate Middleton y la princesa Diana

Descubra por qué un destacado experto en lenguaje corporal cree que es fácil trazar "tales paralelismos" entre la princesa Kate Middleton y la princesa Diana.

Los láseres arrojan luz sobre por qué necesita cerrar la tapa antes de descargar

Los láseres arrojan luz sobre por qué necesita cerrar la tapa antes de descargar

Los inodoros arrojan columnas de aerosol invisibles con cada descarga. ¿Como sabemos? La prueba fue capturada por láseres de alta potencia.

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

¿Caduca el repelente de insectos?

¿Caduca el repelente de insectos?

¿Sigue siendo efectivo ese lote de repelente de insectos que te quedó del verano pasado? Si es así, ¿por cuánto tiempo?

Mire a este policía escalar una situación sin otra razón que ser un idiota

Mire a este policía escalar una situación sin otra razón que ser un idiota

Captura de pantalla del video de Facebook Para aquellos de ustedes que pueden ser demasiado jóvenes para saber esto, antes de que Ice-T fuera una gran estrella en Ley y orden: Unidad de víctimas especiales, era uno de los mejores raperos gangsta de Los Ángeles de todos los tiempos. De hecho, estaba haciendo gangsta rap antes que N.

Reemplace 'Cargado racialmente' por 'Racista' con esta extensión de Chrome

Reemplace 'Cargado racialmente' por 'Racista' con esta extensión de Chrome

Imagen a través de WHAS 11 Algunas cosas realmente podrían tener "carga racial" sin ser racistas. Pero en los principales medios de comunicación, el primero suele ser un código para el segundo.

Proud Mary de Taraji P. Henson es una gran protagonista en busca de una buena película

Proud Mary de Taraji P. Henson es una gran protagonista en busca de una buena película

Foto: Sony Taraji P. Henson, experta tanto en reacciones cáusticas como en expresiones con los ojos húmedos de abrumador conflicto interno, es una actriz dinámica.

Gregg Popovich: LaMarcus Aldridge pidió ser intercambiado este verano, pero ahora estamos bien

Gregg Popovich: LaMarcus Aldridge pidió ser intercambiado este verano, pero ahora estamos bien

Foto: Ronald Martinez / Getty El grandote de los Spurs, LaMarcus Aldridge está teniendo quizás la temporada más eficiente de su carrera mientras reemplaza a Kawhi Leonard como el jugador principal de San Antonio. Mientras que los Warriors y los Rockets están en una carrera armamentista para ver quién puede disparar 100 triples en un juego primero, los Spurs están escondidos detrás de Houston.

Patinaje artístico de EE. UU. 'frustrado' por falta de decisión final en evento por equipos, pide una decisión justa

Patinaje artístico de EE. UU. 'frustrado' por falta de decisión final en evento por equipos, pide una decisión justa

El equipo está a la espera de las medallas que ganó en los Juegos Olímpicos de Invierno de 2022 en Beijing, ya que se está resolviendo un caso de dopaje que involucra a la patinadora artística rusa Kamila Valieva.

Los compradores de Amazon dicen que duermen 'como un bebé mimado' gracias a estas fundas de almohada de seda que cuestan tan solo $ 10

Los compradores de Amazon dicen que duermen 'como un bebé mimado' gracias a estas fundas de almohada de seda que cuestan tan solo $ 10

Miles de compradores de Amazon recomiendan la funda de almohada de seda Mulberry, y está a la venta en este momento. La funda de almohada de seda viene en varios colores y ayuda a mantener el cabello suave y la piel clara. Compre las fundas de almohada de seda mientras tienen hasta un 46 por ciento de descuento en Amazon

Se busca al corredor de los Bengals Joe Mixon por orden de arresto emitida por presuntamente apuntar con un arma de fuego a una mujer

Se busca al corredor de los Bengals Joe Mixon por orden de arresto emitida por presuntamente apuntar con un arma de fuego a una mujer

El jueves se presentó una denuncia de delito menor amenazante agravado contra Joe Mixon.

Profesor de la Universidad de Purdue arrestado por presuntamente traficar metanfetamina y proponer favores sexuales a mujeres

Profesor de la Universidad de Purdue arrestado por presuntamente traficar metanfetamina y proponer favores sexuales a mujeres

El Departamento de Policía de Lafayette comenzó a investigar a un profesor de la Universidad de Purdue en diciembre después de recibir varias denuncias de un "hombre sospechoso que se acercaba a una mujer".

Concept Drift: el mundo está cambiando demasiado rápido para la IA

Concept Drift: el mundo está cambiando demasiado rápido para la IA

Al igual que el mundo que nos rodea, el lenguaje siempre está cambiando. Mientras que en eras anteriores los cambios en el idioma ocurrían durante años o incluso décadas, ahora pueden ocurrir en cuestión de días o incluso horas.

India me está pateando el culo

India me está pateando el culo

Estoy de vuelta por primera vez en seis años. No puedo decirte cuánto tiempo he estado esperando esto.

ℝ

“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.

¿Merrick Garland le ha fallado a Estados Unidos?

Es más de la mitad de la presidencia de Biden. ¿Qué está esperando Merrick Garland?

¿Merrick Garland le ha fallado a Estados Unidos?

Creo, un poco tarde en la vida, en dar oportunidades a la gente. Generosamente.

Language