when then method example done await async jquery asynchronous jquery-deferred decoupling jquery-chaining

method - ¿Cuándo debería usar el método "then" de jQuery diferido y cuándo debería usar el método "pipe"?



jquery submit promise (3)

Dado que jQuery 1.8 .then comporta igual que .pipe :

Aviso de desaprobación : A partir de jQuery 1.8, el método deferred.pipe() está en desuso. El método deferred.then() , que lo reemplaza, se debe usar en su lugar.

y

A partir de jQuery 1.8 , el método deferred.then() devuelve una nueva promesa que puede filtrar el estado y los valores de un diferido a través de una función, reemplazando el ahora deferred.pipe() método deferred.pipe() .

Los ejemplos a continuación aún pueden ser útiles para algunos.

Sirven para diferentes propósitos:

  • .then() debe usarse siempre que desee trabajar con el resultado del proceso, es decir, como dice la documentación, cuando el objeto diferido se resuelve o rechaza. Es lo mismo que usar .done() o .fail() .

  • Utilizarías .pipe() para (pre) filtrar el resultado de alguna manera. El valor de retorno de una devolución de llamada a .pipe() pasará como argumento a las devoluciones de llamada done y fail . También puede devolver otro objeto diferido y las siguientes devoluciones de llamada se registrarán en este diferido.

    Ese no es el caso con .then() (o .done() , .fail() ), los valores devueltos de las devoluciones de llamada registradas simplemente se ignoran.

Entonces, no es que use .then() o .pipe() . Puede usar .pipe() para los mismos fines que .then() pero lo contrario no se cumple.

Ejemplo 1

El resultado de alguna operación es una matriz de objetos:

[{value: 2}, {value: 4}, {value: 6}]

y desea calcular el mínimo y máximo de los valores. Supongamos que utilizamos dos devoluciones de llamada done :

deferred.then(function(result) { // result = [{value: 2}, {value: 4}, {value: 6}] var values = []; for(var i = 0, len = result.length; i < len; i++) { values.push(result[i].value); } var min = Math.min.apply(Math, values); /* do something with "min" */ }).then(function(result) { // result = [{value: 2}, {value: 4}, {value: 6}] var values = []; for(var i = 0, len = result.length; i < len; i++) { values.push(result[i].value); } var max = Math.max.apply(Math, values); /* do something with "max" */ });

En ambos casos, debe iterar sobre la lista y extraer el valor de cada objeto.

¿No sería mejor extraer los valores de antemano de alguna manera para que no tenga que hacer esto en ambas devoluciones de llamadas individualmente? ¡Sí! Y eso es lo que podemos usar .pipe() para:

deferred.pipe(function(result) { // result = [{value: 2}, {value: 4}, {value: 6}] var values = []; for(var i = 0, len = result.length; i < len; i++) { values.push(result[i].value); } return values; // [2, 4, 6] }).then(function(result) { // result = [2, 4, 6] var min = Math.min.apply(Math, result); /* do something with "min" */ }).then(function(result) { // result = [2, 4, 6] var max = Math.max.apply(Math, result); /* do something with "max" */ });

Obviamente, este es un ejemplo inventado y hay muchas formas diferentes (quizás mejores) de resolver este problema, pero espero que ilustre el punto.

Ejemplo 2

Considera las llamadas de Ajax. Algunas veces quiere iniciar una llamada Ajax después de que se complete una anterior. Una forma es hacer la segunda llamada dentro de una devolución de llamada done :

$.ajax(...).done(function() { // executed after first Ajax $.ajax(...).done(function() { // executed after second call }); });

Ahora supongamos que desea desacoplar su código y poner estas dos llamadas Ajax dentro de una función:

function makeCalls() { // here we return the return value of `$.ajax().done()`, which // is the same deferred object as returned by `$.ajax()` alone return $.ajax(...).done(function() { // executed after first call $.ajax(...).done(function() { // executed after second call }); }); }

Le gustaría usar el objeto diferido para permitir que otro código que llame a makeCalls anexe devoluciones de llamada para la segunda llamada Ajax, pero

makeCalls().done(function() { // this is executed after the first Ajax call });

no tendría el efecto deseado ya que la segunda llamada se realiza dentro de una devolución de llamada done y no es accesible desde el exterior.

La solución sería usar .pipe() lugar:

function makeCalls() { // here we return the return value of `$.ajax().pipe()`, which is // a new deferred/promise object and connected to the one returned // by the callback passed to `pipe` return $.ajax(...).pipe(function() { // executed after first call return $.ajax(...).done(function() { // executed after second call }); }); } makeCalls().done(function() { // this is executed after the second Ajax call });

Al utilizar .pipe() , ahora puede hacer que se puedan agregar devoluciones de llamada a la llamada Ajax "interna" sin exponer el flujo / orden real de las llamadas.

En general, los objetos diferidos proporcionan una forma interesante de desacoplar tu código :)

jQuery''s Deferred tiene dos funciones que se pueden utilizar para implementar el encadenamiento asincrónico de funciones:

then()

deferred.then( doneCallbacks, failCallbacks ) Returns: Deferred

doneCallbacks Una función, o conjunto de funciones, que se llama cuando se resuelve el aplazado.
failCallbacks Una función, o conjunto de funciones, que se llama cuando se rechaza el Deferred.

pipe()

deferred.pipe( [doneFilter] [, failFilter] ) Returns: Promise

doneFilter Una función opcional que se llama cuando se resuelve el aplazado .
failFilter Una función opcional que se llama cuando se rechaza el aplazado .

Sé que then() ha estado un poco más tiempo que la pipe() por lo que este último debe agregar algún beneficio adicional, pero lo que la diferencia es precisamente me elude. Ambos toman prácticamente los mismos parámetros de devolución de llamada aunque difieren en su nombre y la diferencia entre devolver un Deferred y devolver una Promise parece leve.

He leído los documentos oficiales una y otra vez, pero siempre los encuentro demasiado "densos" para entenderlos y la búsqueda ha encontrado mucha discusión sobre una u otra característica, pero no he encontrado nada que realmente aclare lo diferente. pros y contras de cada uno.

Entonces, ¿cuándo es mejor usarlo y cuándo es mejor usarlo?

Adición

La excelente respuesta de Félix realmente ayudó a aclarar cómo difieren estas dos funciones. Pero me pregunto si hay momentos en que la funcionalidad de then() es preferible a la de pipe() .

Es evidente que la pipe() es más poderosa que then() y parece que la primera puede hacer cualquier cosa que la segunda pueda hacer. Una de las razones para usar then() podría ser que su nombre refleja su función como la terminación de una cadena de funciones que procesa los mismos datos.

Pero, ¿hay un caso de uso que requiera que then() devuelva el Deferred original que no se puede hacer con pipe() debido a que devuelve un nuevo Promise ?


De hecho, resulta que la diferencia entre .then() y .pipe() se ha considerado innecesaria y se ha hecho que sea la misma que en jQuery versión 1.8.

De un comentario de jaubourg en jQuery''s bug tracker ticket # 11010 "MAKE DEFERRED.THEN == DEFERRED.PIPE LIKE PROMISE / A":

En 1.8, eliminaremos el antiguo y lo reemplazaremos con el tubo actual. Pero la consecuencia más importante es que tendremos que decirle a las personas que utilicen el proceso no hecho, no aprobado y el progreso no estándar, ya que la propuesta no ofrece un medio simple, EFICIENTE, de solo agregar una devolución de llamada.

(énfasis mío)


No hay ningún caso donde DEBES usar then() sobre pipe() . Siempre puede optar por ignorar el valor que pasará pipe() . Puede haber un ligero golpe de rendimiento para usar la pipe , pero es poco probable que importe.

Por lo tanto, podría parecer que siempre puedes usar pipe() en ambos casos. Sin embargo , al usar pipe() , se está comunicando con otras personas que leen su código (incluido usted, dentro de seis meses) que existe cierta importancia para el valor de retorno. Si lo descarta, está violando esta construcción semántica.

Es como tener una función que devuelve un valor que nunca se usa: confuso.

Entonces use then() cuando debería, y pipe() cuando debería ...