jQuery diferido y promesas – .then () vs .done ()

He estado leyendo acerca de las diferciones y promesas de jQuery y no puedo ver la diferencia entre usar .then() y .done() para las devoluciones de llamada exitosas. Sé que Eric Hynds menciona que .done() y .success() asignan a la misma funcionalidad, pero supongo que también .then() ya que todas las devoluciones de llamada se invocan cuando se completa una operación exitosa.

¿Puede alguien por favor aclararme el uso correcto?

Muchas gracias

Las devoluciones de llamada asociadas a done() se dispararán cuando se resuelva el aplazado. Las devoluciones de llamada asociadas a fail() se dispararán cuando se rechace el diferido.

Antes de jQuery 1.8, then() era solo azúcar sintáctico:

 promise.then( doneCallback, failCallback ) // was equivalent to promise.done( doneCallback ).fail( failCallback ) 

A partir de 1.8, then() es un alias para pipe() y devuelve una nueva promesa, consulte aquí para obtener más información sobre pipe() .

success() y error() solo están disponibles en el objeto jqXHR devuelto por una llamada a ajax() . Son alias simples para done() y fail() respectivamente:

 jqXHR.done === jqXHR.success jqXHR.fail === jqXHR.error 

Además, done() no está limitado a una callback única y filtrará las no funciones (aunque hay un error con las cadenas en la versión 1.8 que debería arreglarse en 1.8.1):

 // this will add fn1 to 7 to the deferred's internal callback list // (true, 56 and "omg" will be ignored) promise.done( fn1, fn2, true, [ fn3, [ fn4, 56, fn5 ], "omg", fn6 ], fn7 ); 

Lo mismo ocurre con fail() .

También hay diferencia en la forma en que se procesan los resultados de devolución (se llama encadenamiento, done no encadena mientras que then produce cadenas de llamadas)

 promise.then(function (x) { // Suppose promise returns "abc" console.log(x); return 123; }).then(function (x){ console.log(x); }).then(function (x){ console.log(x) }) 

Los siguientes resultados se registrarán:

 abc 123 undefined 

Mientras

 promise.done(function (x) { // Suppose promise returns "abc" console.log(x); return 123; }).done(function (x){ console.log(x); }).done(function (x){ console.log(x) }) 

obtendrá lo siguiente:

 abc abc abc 

———- Actualización:

Por cierto. Olvidé mencionar que si devuelves Promesa en lugar de valor de tipo atómico, la promesa externa esperará hasta que se resuelva la promesa interna:

 promise.then(function (x) { // Suppose promise returns "abc" console.log(x); return $http.get('/some/data').then(function (result) { console.log(result); // suppose result === "xyz" return result; }); }).then(function (result){ console.log(result); // result === xyz }).then(function (und){ console.log(und) // und === undefined, because of absence of return statement in above then }) 

de esta manera se vuelve muy sencillo componer operaciones asincrónicas paralelas o secuenciales, tales como:

 // Parallel http requests promise.then(function (x) { // Suppose promise returns "abc" console.log(x); var promise1 = $http.get('/some/data?value=xyz').then(function (result) { console.log(result); // suppose result === "xyz" return result; }); var promise2 = $http.get('/some/data?value=uvm').then(function (result) { console.log(result); // suppose result === "uvm" return result; }); return promise1.then(function (result1) { return promise2.then(function (result2) { return { result1: result1, result2: result2; } }); }); }).then(function (result){ console.log(result); // result === { result1: 'xyz', result2: 'uvm' } }).then(function (und){ console.log(und) // und === undefined, because of absence of return statement in above then }) 

El código anterior emite dos solicitudes http en paralelo, lo que hace que las solicitudes se completen antes, mientras que debajo de esas solicitudes http se ejecutan de forma secuencial, lo que reduce la carga del servidor.

 // Sequential http requests promise.then(function (x) { // Suppose promise returns "abc" console.log(x); return $http.get('/some/data?value=xyz').then(function (result1) { console.log(result1); // suppose result1 === "xyz" return $http.get('/some/data?value=uvm').then(function (result2) { console.log(result2); // suppose result2 === "uvm" return { result1: result1, result2: result2; }; }); }); }).then(function (result){ console.log(result); // result === { result1: 'xyz', result2: 'uvm' } }).then(function (und){ console.log(und) // und === undefined, because of absence of return statement in above then }) 

.done() tiene solo una callback y es la callback de éxito

.then() tiene devoluciones de llamadas exitosas y fallidas

.fail() solo tiene una callback fallida

entonces depende de usted lo que debe hacer … ¿le importa si tiene éxito o si falla?

deferred.done ()

Agrega manejadores para llamar solo cuando se resuelve Deferido . Puede agregar múltiples devoluciones de llamada para ser llamado.

 var url = 'http://jsonplaceholder.typicode.com/posts/1'; $.ajax(url).done(doneCallback); function doneCallback(result) { console.log('Result 1 ' + result); } 

También puede escribir arriba de esta manera,

 function ajaxCall() { var url = 'http://jsonplaceholder.typicode.com/posts/1'; return $.ajax(url); } $.when(ajaxCall()).then(doneCallback, failCallback); 

deferred.then ()

Agrega manejadores a ser llamados cuando se aprueba, rechaza o aún está en progreso .

 var url = 'http://jsonplaceholder.typicode.com/posts/1'; $.ajax(url).then(doneCallback, failCallback); function doneCallback(result) { console.log('Result ' + result); } function failCallback(result) { console.log('Result ' + result); } 

En realidad, hay una diferencia bastante crítica, en la medida en que los Deferreds de jQuery están destinados a ser una implementación de Promises (y jQuery3.0 realmente intenta ponerlos en la especificación).

La diferencia clave entre done / then es que

  • .done() SIEMPRE devuelve los mismos valores Promesa / envuelto con los que comenzó, independientemente de lo que haga o devuelva.
  • .then() siempre devuelve una NUEVA Promesa, y usted está a cargo de controlar qué Promesa se basa en la función que le devolvió.

Traducido de jQuery a ES2015 Promises nativo, .done() es como implementar una estructura de “tap” alrededor de una función en una cadena Promise, en la que, si la cadena está en el estado “resolver”, pasará un valor a una función … pero el resultado de esa función NO afectará a la cadena en sí.

 const doneWrap = fn => x => { fn(x); return x }; Promise.resolve(5) .then(doneWrap( x => x + 1)) .then(doneWrap(console.log.bind(console))); $.Deferred().resolve(5) .done(x => x + 1) .done(console.log.bind(console)); 

Esos registrarán 5, no 6.

Tenga en cuenta que utilicé done y doneWrap para hacer logging, no .then. Eso es porque las funciones de console.log en realidad no devuelven nada. ¿Y qué pasa si pasas, entonces, una función que no devuelve nada?

 Promise.resolve(5) .then(doneWrap( x => x + 1)) .then(console.log.bind(console)) .then(console.log.bind(console)); 

Eso se registrará:

5

indefinido

¿Que pasó? Cuando usé .then y le pasé una función que no devolvió nada, su resultado implícito fue “indefinido” … que por supuesto devolvió una Promesa [indefinida] al siguiente método, que no se definió. Entonces el valor original con el que comenzamos se perdió básicamente.

.then() es, en el fondo, una forma de composición de funciones: el resultado de cada paso se usa como argumento para la función en el siguiente paso. Por eso .done se considera mejor como un “toque” -> en realidad no es parte de la composición, solo algo que eche un vistazo al valor en un cierto paso y ejecuta una función a ese valor, pero en realidad no altera la composición de cualquier manera.

Esta es una diferencia bastante fundamental, y es probable que haya una buena razón por la cual las Promesas nativas no tienen implementado un método .done. No tenemos que entrar en por qué no hay un método .fail, porque eso es aún más complicado (es decir, .fail / .catch NO son espejos de las funciones .done / .then -> en .catch que devuelven los valores básicos no “quedarse” rechazado como los que pasaron. Entonces, ¡se resuelven!)

then() siempre significa que se llamará en cualquier caso. Pero los parámetros que pasan son diferentes en diferentes versiones de jQuery.

Antes de jQuery 1.8, then() es igual a done().fail() . Y todas las funciones de callback comparten los mismos parámetros.

Pero a partir de jQuery 1.8, then() devuelve una nueva promesa, y si ha devuelto un valor, se pasará a la siguiente función de callback.

Veamos el siguiente ejemplo:

 var defer = jQuery.Deferred(); defer.done(function(a, b){ return a + b; }).done(function( result ) { console.log("result = " + result); }).then(function( a, b ) { return a + b; }).done(function( result ) { console.log("result = " + result); }).then(function( a, b ) { return a + b; }).done(function( result ) { console.log("result = " + result); }); defer.resolve( 3, 4 ); 

Antes de jQuery 1.8, la respuesta debería ser

 result = 3 result = 3 result = 3 

Todos los result toman 3. Y then() función siempre pasa el mismo objeto diferido a la siguiente función.

Pero a partir de jQuery 1.8, el resultado debería ser:

 result = 3 result = 7 result = NaN 

Debido a que la primera función then() devuelve una nueva promesa, y el valor 7 (y este es el único parámetro que se transmitirá) se pasa al siguiente done() , por lo que el segundo done() escribe result = 7 . El segundo then() toma 7 como el valor de a y toma undefined como el valor de b , entonces el segundo then() devuelve una nueva promesa con el parámetro NaN, y el último done() imprime NaN como resultado.

Hay una asignación mental muy simple en respuesta que fue un poco difícil de encontrar en las otras respuestas:

  • done implementa tap como en bluebird Promises

  • then implementa then como en ES6 Promises

.done() finaliza la cadena de promesa, asegurándose de que nada más pueda adjuntar pasos adicionales. Esto significa que la implementación jQuery promise puede arrojar cualquier excepción no controlada, ya que nadie puede manejarla usando .fail() .

En términos prácticos, si no planea adjuntar más pasos a una promesa, debe usar .done() . Para más detalles ver por qué hay que hacer promesas