¿Cuáles son las diferencias entre diferido, promesa y futuro en JavaScript?


300

¿Cuáles son las diferencias entre diferidos, promesas y futuros?
¿Existe una teoría generalmente aprobada detrás de estos tres?


11
No creo que esto tenga nada que ver con jQuery ...
BoltClock


8
No los he usado yo mismo, pero aquí hay una muy buena introducción en wikipedia en.wikipedia.org/wiki/Futures_and_promises . Aunque no entiendo completamente el caso de uso correctamente. En un evento asíncrono impulsado por lenguaje como javascript. A primera vista, no puedo ver lo que ofrecen sobre devoluciones de llamada, aparte de quizás una API más limpia. Me encantaría que alguien pudiera proporcionar un ejemplo de caso de uso y mostrar cómo se aplican estos conceptos y por qué las devoluciones de llamada serían una solución ineficiente. @duri esto no tiene nada que ver con jQuery. ¿Se puede eliminar la etiqueta jQuery
AshHeskes

2
@ jfriend00 gran enlace, probablemente debería trabajar en una respuesta.
fncomp

Respuestas:


97

A la luz del aparente disgusto por cómo he intentado responder a la pregunta del OP. La respuesta literal es, una promesa es algo compartido con otros objetos, mientras que un diferido debe mantenerse privado. Principalmente, un diferido (que generalmente extiende Promesa) puede resolverse por sí mismo, mientras que una promesa podría no ser capaz de hacerlo.

Si está interesado en las minucias, examine Promesas / A + .


Hasta donde sé, el propósito general es mejorar la claridad y aflojar el acoplamiento a través de una interfaz estandarizada. Vea la lectura sugerida de @ jfriend00:

En lugar de pasar directamente las devoluciones de llamada a las funciones, algo que puede conducir a interfaces estrechamente acopladas, el uso de promesas permite separar las preocupaciones por el código que es síncrono o asíncrono.

Personalmente, he encontrado que diferir es especialmente útil cuando se trata, por ejemplo, de plantillas pobladas por solicitudes asíncronas, cargando scripts que tienen redes de dependencias y proporcionando comentarios de los usuarios para formar datos de manera no bloqueante.

De hecho, compare la forma de devolución de llamada pura de hacer algo después de cargar CodeMirror en modo JS de forma asíncrona (disculpas, no he usado jQuery en un tiempo ):

/* assume getScript has signature like: function (path, callback, context) 
   and listens to onload && onreadystatechange */
$(function () {
   getScript('path/to/CodeMirror', getJSMode);

   // onreadystate is not reliable for callback args.
   function getJSMode() {
       getScript('path/to/CodeMirror/mode/javascript/javascript.js', 
           ourAwesomeScript);
   };

   function ourAwesomeScript() {
       console.log("CodeMirror is awesome, but I'm too impatient.");
   };
});

Para la versión formulada de promesas (nuevamente, disculpas, no estoy actualizado en jQuery):

/* Assume getScript returns a promise object */
$(function () {
   $.when(
       getScript('path/to/CodeMirror'),
       getScript('path/to/CodeMirror/mode/javascript/javascript.js')
   ).then(function () {
       console.log("CodeMirror is awesome, but I'm too impatient.");
   });
});

Disculpas por el semi-pseudocódigo, pero espero que aclare la idea central. Básicamente, al devolver una promesa estandarizada, puede pasar la promesa, lo que permite una agrupación más clara.


10
Si bien esta respuesta puede ser útil, en realidad no aborda la cuestión: los llamados diferidos son futuros o promesas, dependiendo de la implementación.
awdz9nld

@ MartinKällman Tienes razón! No había vuelto a visitar esto en mucho tiempo y he aprendido un poco. Publicaré una respuesta por separado a continuación, pero deje esto ya que las personas parecen haberse beneficiado del ejemplo de uso.
fncomp

@ MartinKällman, consideró escribir una nueva respuesta. Sin embargo, creo que el OP realmente quería saber para qué son las Promesas y Aplazamientos. La respuesta a su pregunta real sería, más o menos, "los diferidos pueden resolverse por sí mismos. AFAIK, la teoría detrás de las promesas y los diferidos proviene de [Functional Reactive Programming | haskell.org/haskellwiki/Functional_Reactive_Programming] , que es una técnica para aplanar las devoluciones de llamada ".
fncomp

2
Esto es totalmente incorrecto y sus ejemplos son tan fáciles de hacer con devoluciones de llamada. Las promesas no se refieren a la agregación y el desacoplamiento de devolución de llamada, sino a proporcionar un DSL para escribir código asíncrono como se escribe el código de sincronización. Especialmente fn(callback, errback)no está más estrechamente acoplado o es menos útil que fn().then(callback, errback)eso, pero esa es una forma incorrecta de usar promesas de todos modos. Especialmente odio el $.whenejemplo de culto a la carga : no hay absolutamente ninguna razón por la que no pueda tener una $.whenfunción que funcione con devoluciones de llamada.
Esailija

Sin embargo, esto no responde a la pregunta +1 de que podría saber cuál es el infierno de devolución de llamada.
Bhojendra Rauniyar

146

Estas respuestas, incluyendo la respuesta seleccionada, son buenos para la introducción de las promesas de vista conceptual, pero carece de detalles de lo que exactamente las diferencias están en la terminología que surge cuando se utilizan las bibliotecas aplicación (y no son diferencias importantes).

Como todavía es una especificación en evolución , la respuesta actualmente proviene de intentar encuestar tanto las referencias (como wikipedia ) como las implementaciones (como jQuery ):

  • Diferido : nunca descrito en referencias populares, 1 2 3 4 pero comúnmente utilizado por implementaciones como el árbitro de la resolución de promesa (implementación y ). 5 6 7 resolvereject

    A veces, los diferidos también son promesas (implementación then), 5 6 otras veces se considera más puro tener el diferido solo capaz de resolución, y obligando al usuario a acceder a la promesa de uso . 7 7 then

  • Promesa : La palabra más completa para la estrategia en discusión.

    Un objeto proxy que almacena el resultado de una función objetivo cuya sincronía nos gustaría abstraer, además de exponer una thenfunción que acepta otra función objetivo y devuelve una nueva promesa. 2

    Ejemplo de CommonJS :

    > asyncComputeTheAnswerToEverything()
        .then(addTwo)
        .then(printResult);
    44
    

     

    Siempre se describe en referencias populares, aunque nunca se especifica a qué responsabilidad corresponde la resolución. 1 2 3 4

    Siempre presente en implementaciones populares, y nunca con capacidad de resolución. 5 6 7

  • Futuro : un término aparentemente obsoleto que se encuentra en algunas referencias populares 1 y al menos en una implementación popular, 8 pero que parece estar fuera de discusión con preferencia por el término 'promesa' 3 y no siempre se menciona en introducciones populares al tema. 9 9

    Sin embargo, al menos una biblioteca usa el término genéricamente para abstraer la sincronicidad y el manejo de errores, sin proporcionar thenfuncionalidad. 10 No está claro si evitar el término "promesa" fue intencional, pero probablemente sea una buena opción, ya que las promesas se basan en los "materiales". 2

Referencias

  1. Wikipedia sobre promesas y futuros
  2. Promesas / especificaciones A +
  3. Norma DOM sobre promesas
  4. DOM estándar promete especificaciones WIP
  5. DOJO Toolkit Diferidos
  6. jQuery diferidos
  7. Q
  8. FutureJS
  9. Sección Javascript funcional sobre promesas
  10. Futuros en pruebas de integración de AngularJS

Varias cosas potencialmente confusas


55
Para agregar un poco más de aclaración sobre el término "Futuro", los futuros tienen una larga historia en muchos lenguajes de programación que datan de mediados de los 80. Y el término todavía se usa ampliamente hoy, en particular en la JVM. Parece que JavaScript eligió usar el término "Promesa" para significar algo similar a lo que Java quiere decir con "Futuro". Scala separa el mismo concepto en un "Futuro" y "Promesa" para referirse al identificador de "lectura" y el identificador de "escritura" de lo que los programadores de JavaScript llaman Promesa.
Heather Miller

1
Y, por supuesto, Microsoft tuvo que idear su propio término para eso, así que en C # se les llamaTask
BlueRaja, Danny Pflughoeft,

72

Lo que realmente hizo que todo fuera clic para mí fue esta presentación de Domenic Denicola.

En un github gist , dio la descripción que más me gusta, es muy conciso:

El objetivo de las promesas es devolvernos la composición funcional y el burbujeo de errores en el mundo asíncrono.

En otras palabras, las promesas son una forma que nos permite escribir código asincrónico que es casi tan fácil de escribir como si fuera síncrono .

Considere este ejemplo, con promesas:

getTweetsFor("domenic") // promise-returning async function
    .then(function (tweets) {
        var shortUrls = parseTweetsForUrls(tweets);
        var mostRecentShortUrl = shortUrls[0];
        return expandUrlUsingTwitterApi(mostRecentShortUrl); // promise-returning async function
    })
    .then(doHttpRequest) // promise-returning async function
    .then(
        function (responseBody) {
            console.log("Most recent link text:", responseBody);
        },
        function (error) {
            console.error("Error with the twitterverse:", error);
        }
    );

Funciona como si estuviera escribiendo este código síncrono:

try {
    var tweets = getTweetsFor("domenic"); // blocking
    var shortUrls = parseTweetsForUrls(tweets);
    var mostRecentShortUrl = shortUrls[0];
    var responseBody = doHttpRequest(expandUrlUsingTwitterApi(mostRecentShortUrl)); // blocking x 2
    console.log("Most recent link text:", responseBody);
} catch (error) {
    console.error("Error with the twitterverse: ", error);
}

(Si esto todavía suena complicado, ¡mira esa presentación!)

En cuanto a diferido, es una forma .resolve()o .reject()promesas. En la especificación Promises / B , se llama .defer(). En jQuery, lo es $.Deferred().

Tenga en cuenta que, hasta donde yo sé, la implementación de Promise en jQuery está rota (vea lo esencial), al menos a partir de jQuery 1.8.2.
Supuestamente implementa Promesas / A thenables , pero no obtienes el manejo correcto de errores que deberías, en el sentido de que toda la funcionalidad "async try / catch" no funcionará. Lo cual es una pena, porque tener un "try / catch" con código asíncrono es absolutamente genial.

Si va a usar Promesas (¡debería probarlas con su propio código!), Use la Q de Kris Kowal . La versión de jQuery es solo un agregador de devolución de llamada para escribir código jQuery más limpio, pero pierde el punto.

Con respecto al futuro, no tengo idea, no lo he visto en ninguna API.

Editar: la charla de YouTube de Domenic Denicola sobre Promesas del comentario de @Farm a continuación.

Una cita de Michael Jackson (sí, Michael Jackson ) del video:

Quiero que quemes esta frase en tu mente: una promesa es un valor asincrónico .

Esta es una excelente descripción: una promesa es como una variable del futuro: una referencia de primera clase a algo que, en algún momento, existirá (o sucederá).


55
Aquí encontrará una gran explicación de Futures (¡ahora implementada en el DOM!) Por un miembro del equipo principal de W3 y Chrome: xanthir.com/b4PY0
oligofren

1
@oligofren Gracias por el enlace, ¡eso parece lindo! Por cierto, qué favicon misteriosamente molesto jajaja.
Camilo Martin

1
Esta respuesta necesita muchos más votos a favor. Se debe votar más alto que la respuesta aceptada de la OMI.
Chev

1
Charla de YouTube de Domenic Denicola sobre Promesas: youtube.com/watch?v=hf1T_AONQJU
Granja

@ Granja ¡Genial! Agregaré eso a la respuesta.
Camilo Martin

32

Una promesa representa un proxy para un valor no necesariamente conocido cuando se crea la promesa. Le permite asociar controladores a un valor de éxito eventual de una acción asincrónica o una razón de falla. Esto permite que los métodos asincrónicos devuelvan valores como los métodos sincrónicos: en lugar del valor final, el método asincrónico promete tener un valor en algún momento en el futuro.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

El deferred.promise()método permite una función asincrónica para evitar que otro código interfiera con el progreso o el estado de su solicitud interna. La Promesa expone solo los métodos diferidos necesarios para adjuntar controladores adicionales o determinar el estado ( luego, hecho, falla, siempre, canalización, progreso, estado y promesa ), pero no los que cambian el estado ( resolver, rechazar, notificar, resolver con, rechazar con y notificar con ).

Si se proporciona el objetivo, deferred.promise()adjuntará los métodos en él y luego devolverá este objeto en lugar de crear uno nuevo. Esto puede ser útil para adjuntar el comportamiento Promesa a un objeto que ya existe.

Si está creando un diferido, mantenga una referencia al diferido para que pueda resolverse o rechazarse en algún momento. Devuelva solo el objeto Promise a través de deferred.promise () para que otro código pueda registrar devoluciones de llamada o inspeccionar el estado actual.

Simplemente podemos decir que una Promesa representa un valor que aún no se conoce, mientras que un Diferido representa un trabajo que aún no está terminado.


ingrese la descripción de la imagen aquí


1
más 1 para la representación del gráfico. Bravisimo !! ^ _ ^
Ashok MA

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.