He estado leyendo sobre jQuery diferidos y promesas y no puedo ver la diferencia entre usar .then()
& .done()
para devoluciones de llamada exitosas. Sé que Eric Hynds menciona eso .done()
y se .success()
asigna a la misma funcionalidad, pero supongo que sí, .then()
ya que todas las devoluciones de llamada se invocan al completar una operación exitosa.
¿Alguien puede iluminarme para el uso correcto?
jquery
promise
jquery-deferred
screenm0nkey
fuente
fuente
Respuestas:
Las devoluciones de llamada adjuntas se
done()
activarán cuando se resuelva el aplazado. Las devoluciones de llamada adjuntas sefail()
activarán cuando se rechace el aplazado.Antes de jQuery 1.8,
then()
era solo azúcar sintáctico:A partir de 1.8,
then()
es un aliaspipe()
y devuelve una nueva promesa, consulte aquí para obtener más informaciónpipe()
.success()
yerror()
solo están disponibles en eljqXHR
objeto devuelto por una llamada aajax()
. Son alias simples paradone()
yfail()
respectivamente:Además,
done()
no se limita a una única devolución de llamada y filtrará las no funciones (aunque hay un error con cadenas en la versión 1.8 que debería corregirse en 1.8.1):Lo mismo vale para
fail()
.fuente
then
devolver una nueva promesa fue algo clave que me faltaba. No podía entender por qué una cadena como$.get(....).done(function(data1) { return $.get(...) }).done(function(data2) { ... })
estaba fallando condata2
indefinido; cuando cambiédone
athen
esto funcionó, porque realmente quería canalizar las promesas juntas en lugar de adjuntar más controladores a la promesa original.done
othen
? ¿Por qué?.then()
).También hay una diferencia en la forma en que se procesan los resultados de retorno (se llama encadenamiento,
done
no se encadena mientrasthen
produce cadenas de llamadas)Se registrarán los siguientes resultados:
Mientras
obtendrá lo siguiente:
---------- Actualización:
Por cierto. Olvidé mencionar que si devuelve una Promesa en lugar del valor de tipo atómico, la promesa externa esperará hasta que se resuelva la promesa interna:
de esta manera se vuelve muy sencillo componer operaciones asincrónicas paralelas o secuenciales como:
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 secuencialmente, lo que reduce la carga del servidor
fuente
done
no hace nada al resultado dondethen
cambia el resultado. Enorme punto perdido por los demás imo.then
cambió en 1.8done
y dethen
llamadas.done
ejemplo. Cambiethen
apipe
pre-1.8 para obtener elthen
comportamiento 1.8+ ..done()
solo tiene una devolución de llamada y es la devolución de llamada exitosa.then()
tiene devoluciones de llamada exitosas y fallidas.fail()
solo tiene una devolución de llamada fallidaentonces depende de usted lo que debe hacer ... ¿le importa si tiene éxito o si falla?
fuente
then()
muy diferentes dedone()
. Como athen()
menudo se llama solo con la devolución de llamada exitosa, su punto es más un detalle que lo principal para recordar / conocer. (No puedo decir cómo era antes de jQuery 3.0.)diferido.done ()
agrega manejadores a los que se llamará solo cuando se resuelva Diferido . Puede agregar múltiples devoluciones de llamada para ser llamado.
También puedes escribir arriba así,
deferred.then ()
agrega manejadores a los que se llama cuando se difiere, se rechaza o aún está en progreso .
fuente
then
comporta si nofail
se proporciona una devolución de llamada, es decir, no captura elfail
caso en absolutoEn realidad, hay una diferencia bastante crítica, en la medida en que los aplazamientos de jQuery están destinados a ser implementaciones de Promesas (y jQuery3.0 en realidad trata de ponerlas en especificación).
La diferencia clave entre hecho / entonces es que
.done()
SIEMPRE devuelve los mismos valores Promise / wrap con los que comenzó, independientemente de lo que haga o lo que 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 Promesas ES2015 nativas,
.done()
es como implementar una estructura "tap" alrededor de una función en una cadena Promise, en el sentido de 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á la cadena en sí.Ambos registrarán 5, no 6.
Tenga en cuenta que usé done y doneWrap para hacer el registro, no .then. Eso es porque las funciones de console.log en realidad no devuelven nada. ¿Y qué pasa si pasa .then una función que no devuelve nada?
Eso registrará:
¿Que pasó? Cuando utilicé .then y le pasé una función que no devolvió nada, su resultado implícito fue "indefinido" ... lo que, por supuesto, devolvió una Promesa [indefinida] al siguiente método, que se registró indefinido. 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. Es por eso que .done se considera mejor como un "toque" -> en realidad no es parte de la composición, solo algo que muestra un poco el valor en un determinado paso y ejecuta una función en ese valor, pero en realidad no altera La composición de cualquier manera.Esta es una diferencia bastante fundamental, y probablemente haya una buena razón por la cual las Promesas nativas no tienen implementado un método .done. No tenemos que entender por qué no hay un método .fail, porque eso es aún más complicado (a saber, .fail / .catch NO son espejos de las funciones .done / .then -> en .catch que devuelven valores simples no "permanecer" rechazado como los que se pasan a. ¡Entonces, se resuelven!)
fuente
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 igualdone().fail()
. Y todas las funciones de devolución de llamada 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 devolución de llamada.Veamos el siguiente ejemplo:
Antes de jQuery 1.8, la respuesta debería ser
Todo
result
toma 3. Y lathen()
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:
Debido a que la primera
then()
función devuelve una nueva promesa, y el valor 7 (y este es el único parámetro que se transmitirá) se pasa a la siguientedone()
, por lo que la segundadone()
escrituraresult = 7
. El segundothen()
toma 7 como valor dea
y tomaundefined
como valor deb
, por lo que el segundothen()
devuelve una nueva promesa con el parámetro NaN, y el últimodone()
imprime NaN como resultado.fuente
jQuery.Deferred()
puede recibir múltiples valores, que pasa correctamente al primero.then()
. Sin embargo, es un poco extraño ... ya que cualquiera de los siguientes.then()
no puede hacerlo. (La interfaz elegida a través dereturn
solo puede devolver un valor). El nativo de JavascriptPromise
no hace eso. (Lo cual es más consistente, para ser honesto)Hay un mapeo mental muy simple en respuesta que fue un poco difícil de encontrar en las otras respuestas:
done
implementatap
como en Bluebird Promisesthen
implementathen
como en ES6 Promesasfuente
Uso único
.then()
Estas son las desventajas de
.done()
resolve()
llamada (todos los.done()
controladores se ejecutarán sincrónicamente)resolve()
podría obtener una excepción de los.done()
controladores registrados (!).done()
medio mata al diferido:.done()
se omitirán silenciosamente otros controladoresPensé temporalmente que
.then(oneArgOnly)
siempre se requiere.catch()
para que no se ignore ninguna excepción en silencio, pero eso ya no es cierto: elunhandledrejection
evento registra.then()
excepciones no controladas en la consola (por defecto). ¡Muy razonable! No hay razón para usar.done()
en absoluto.Prueba
El siguiente fragmento de código revela que:
.done()
manejadores se llamarán sincrónicos en el punto deresolve()
.done()
influenciasresolve()
resolve()
.done()
resolución.then()
no tiene ninguno de estos problemasunhandledrejection
es parece)Por cierto, las excepciones de
.done()
no se pueden capturar correctamente: debido al patrón sincrónico de.done()
, el error se produce en el punto de.resolve()
(¡podría ser el código de la biblioteca!) O en la.done()
llamada que une al culpable si el diferido ya está resuelto.fuente
done
no se ejecutará si un hecho anterior tiene una excepción. Pero por qué sería ignorado en silencio, quiero decir que ocurrió una excepción, entonces ¿por qué dices que es silencioso? 2) Desprecio elDeferred
objeto porque su API está muy mal hecha. Es demasiado complejo y confuso. Su código aquí tampoco ayuda a probar su punto y tiene demasiada complejidad innecesaria para lo que está tratando de probar. 3) ¿Por qué losdone
índices 2, 4 y 6 se realizan antes del segundothen
?.then()
serán llamados, excepción (en esos controladores) planteados o no. Pero además /.done()
descanso restante .Hay una diferencia vital más a partir de jQuery 3.0 que puede conducir fácilmente a un comportamiento inesperado y no se menciona en las respuestas anteriores:
Considere el siguiente código:
esto dará como resultado:
Ahora, reemplace
done()
porthen()
en el mismo fragmento:la salida es ahora:
Por lo tanto, para los aplazamientos resueltos de inmediato, la función pasada a
done()
siempre se invocará de forma síncrona, mientras que cualquier argumento pasado athen()
se invoca de forma asíncrona.Esto difiere de las versiones anteriores de jQuery donde ambas devoluciones de llamada se llaman sincrónicamente, como se menciona en la guía de actualización :
fuente
.done()
termina la cadena de promesa, asegurándose de que nada más pueda adjuntar más pasos. Esto significa que la implementación de la promesa jQuery 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 usarlos
.done()
. Para más detalles, vea por qué las promesas deben hacersefuente
.done()
no tiene un rol de terminación. La documentación dice: "Dado que deferred.done () devuelve el objeto diferido, otros métodos del objeto diferido se pueden encadenar a este, incluidos los métodos adicionales .done ()"..fail()
no se menciona, pero sí, eso también podría estar encadenado.