J'ai lu sur les différés et les promesses de jQuery et je ne vois pas la différence entre l'utilisation de .then()
& .done()
pour des rappels réussis. Je sais que Eric Hynds le mentionne .done()
et .success()
mappe à la même fonctionnalité, mais je suppose que c'est le cas, .then()
car tous les rappels sont tous invoqués à la fin d'une opération réussie.
Quelqu'un peut-il m'éclairer sur l'utilisation correcte?
jquery
promise
jquery-deferred
screenm0nkey
la source
la source
Réponses:
Les rappels associés à
done()
seront renvoyés lorsque le différé est résolu. Les rappels associés àfail()
seront renvoyés lorsque le différé est rejeté.Avant jQuery 1.8,
then()
était juste du sucre syntaxique:Depuis la version 1.8,
then()
est un aliaspipe()
et renvoie une nouvelle promesse, voir ici pour plus d'informationspipe()
.success()
eterror()
ne sont disponibles que sur l'jqXHR
objet renvoyé par un appel àajax()
. Ce sont des alias simples pourdone()
etfail()
respectivement:De plus,
done()
n'est pas limité à un seul rappel et filtrera les non-fonctions (bien qu'il y ait un bug avec des chaînes dans la version 1.8 qui devrait être corrigé dans 1.8.1):Il en va de même
fail()
.la source
then
retourner une nouvelle promesse était une chose clé qui me manquait. Je ne pouvais pas comprendre pourquoi une chaîne comme$.get(....).done(function(data1) { return $.get(...) }).done(function(data2) { ... })
échouait avecdata2
undefined; quand je suis passédone
àthen
ça a fonctionné, parce que je voulais vraiment diriger les promesses ensemble plutôt que d'attacher plus de gestionnaires à la promesse d'origine.done
outhen
? Pourquoi?.then()
).Il y a aussi une différence dans la façon dont les résultats de retour sont traités (son appelé chaînage,
done
ne chaîne pas tout enthen
produisant des chaînes d'appel)Les résultats suivants seront enregistrés:
Tandis que
obtiendra ce qui suit:
---------- Mise à jour:
Btw. J'ai oublié de mentionner que si vous renvoyez une promesse au lieu d'une valeur de type atomique, la promesse extérieure attendra que la promesse intérieure soit résolue:
de cette façon, il devient très simple de composer des opérations asynchrones parallèles ou séquentielles telles que:
Le code ci-dessus émet deux requêtes http en parallèle, ce qui rend les requêtes terminées plus tôt, tandis qu'en dessous de ces requêtes http sont exécutées séquentiellement, réduisant ainsi la charge du serveur
la source
done
ne fait rien au résultat oùthen
change le résultat. Énorme point raté par les autres imo.then
changé en 1.8done
et desthen
résultats.done
exemple. Passezthen
à la versionpipe
antérieure à 1.8 pour obtenir lethen
comportement 1.8+ ..done()
n'a qu'un seul rappel et c'est le rappel de réussite.then()
a à la fois des rappels de réussite et d'échec.fail()
n'a qu'un seul échec de rappelc'est à vous de décider ce que vous devez faire ... vous souciez-vous si cela réussit ou s'il échoue?
la source
then()
très différentes dedone()
. Commethen()
on l'appelle souvent uniquement avec le rappel de réussite, votre point est plutôt un détail que la chose principale à retenir / savoir. (Je ne peux pas dire comment c'était avant jQuery 3.0.)deferred.done ()
ajoute des gestionnaires à appeler uniquement lorsque la résolution différée est résolue . Vous pouvez ajouter plusieurs rappels à appeler.
Vous pouvez également écrire ci-dessus comme ceci,
deferred.then ()
ajoute des gestionnaires à appeler lorsque le report est résolu, rejeté ou encore en cours .
la source
then
se comporte si aucunfail
rappel n'est fourni - à savoir ne pas capturer lefail
cas du toutIl y a en fait une différence assez critique, dans la mesure où les différés de jQuery sont censés être des implémentations de Promises (et jQuery3.0 essaie en fait de les mettre en spécification).
La principale différence entre done / then est que
.done()
TOUJOURS renvoie les mêmes valeurs promises / encapsulées avec lesquelles il a commencé, indépendamment de ce que vous faites ou de ce que vous retournez..then()
renvoie toujours une NOUVELLE promesse, et vous êtes en charge de contrôler ce que cette promesse est basée sur ce que la fonction que vous avez passée l'a renvoyée.Traduit de jQuery en promesses natives ES2015,
.done()
c'est un peu comme implémenter une structure "tap" autour d'une fonction dans une chaîne Promise, en ce sens que, si la chaîne est à l'état "résoudre", transmettre une valeur à une fonction. mais le résultat de cette fonction n'affectera PAS la chaîne elle-même.Ceux-ci enregistreront tous les deux 5, pas 6.
Notez que j'ai utilisé done et doneWrap pour faire la journalisation, pas .then. C'est parce que les fonctions console.log ne renvoient en fait rien. Et que se passe-t-il si vous passez. Puis une fonction qui ne renvoie rien?
Cela enregistrera:
Qu'est-il arrivé? Lorsque j'ai utilisé .then et que je lui ai transmis une fonction qui ne renvoyait rien, son résultat implicite était "non défini" ... ce qui bien sûr renvoyait une promesse [non définie] à la méthode then suivante, qui se connectait non définie. La valeur d'origine avec laquelle nous avons commencé a donc été essentiellement perdue.
.then()
est, au fond, une forme de composition de fonction: le résultat de chaque étape est utilisé comme argument pour la fonction à l'étape suivante. C'est pourquoi .done est mieux considéré comme un "tap" -> il ne fait pas réellement partie de la composition, juste quelque chose qui jette un œil à la valeur à une certaine étape et exécute une fonction à cette valeur, mais ne modifie pas réellement la composition en aucune façon.C'est une différence assez fondamentale, et il y a probablement une bonne raison pour laquelle les Promesses natives n'ont pas elles-mêmes implémenté une méthode .done. Nous n'avons pas besoin de comprendre pourquoi il n'y a pas de méthode .fail, car c'est encore plus compliqué (à savoir, .fail / .catch ne sont PAS des miroirs des fonctions .done / .then -> dans .catch qui renvoient des valeurs nues ne le font pas "rester" rejeté comme ceux passés à. puis, ils résolvent!)
la source
then()
signifie toujours qu'il sera appelé dans tous les cas. Mais les paramètres qui passent sont différents dans les différentes versions de jQuery.Avant jQuery 1.8,
then()
est égal àdone().fail()
. Et toutes les fonctions de rappel partagent les mêmes paramètres.Mais à partir de jQuery 1.8,
then()
retourne une nouvelle promesse, et si elle a renvoyé une valeur, elle sera passée dans la prochaine fonction de rappel.Voyons l'exemple suivant:
Avant jQuery 1.8, la réponse devrait être
Tout
result
prend 3. Et lathen()
fonction passe toujours le même objet différé à la fonction suivante.Mais à partir de jQuery 1.8, le résultat devrait être:
Parce que la première
then()
fonction renvoie une nouvelle promesse, et la valeur 7 (et c'est le seul paramètre qui sera transmis) est passée à la suivantedone()
, donc la deuxièmedone()
écritureresult = 7
. La secondethen()
prend 7 comme valeur dea
et prendundefined
comme valeur deb
, donc la secondethen()
renvoie une nouvelle promesse avec le paramètre NaN, et la dernièredone()
affiche NaN comme résultat.la source
jQuery.Deferred()
puisse recevoir plusieurs valeurs, qu'il transmet correctement à la première.then()
. - Un peu étrange cependant ... comme les suivants.then()
ne peuvent pas le faire. (L'interface choisie viareturn
ne peut renvoyer qu'une seule valeur.) Le natif de JavascriptPromise
ne fait pas cela. (Ce qui est plus cohérent, pour être honnête.)Il y a une cartographie mentale très simple en réponse qui était un peu difficile à trouver dans les autres réponses:
done
implémentetap
comme dans Bluebird Promisesthen
implémentethen
comme dans ES6 Promisesla source
Usage unique
.then()
Ce sont les inconvénients de
.done()
resolve()
appel (tous les.done()
gestionnaires seront exécutés de manière synchrone)resolve()
peut obtenir une exception de la part des.done()
gestionnaires enregistrés (!).done()
demi-tue le différé:.done()
gestionnaires seront ignorés en silenceJ'ai pensé temporairement que cela
.then(oneArgOnly)
nécessite toujours.catch()
pour qu'aucune exception ne soit silencieusement ignorée, mais ce n'est plus vrai: l'unhandledrejection
événement enregistre les.then()
exceptions non gérées sur la console (par défaut). Très raisonnable! Aucune raison de l'utiliser.done()
.Preuve
L'extrait de code suivant révèle que:
.done()
gestionnaires seront appelés synchrones au point deresolve()
.done()
influencesresolve()
resolve()
.done()
résolution.then()
n'a aucun de ces problèmesunhandledrejection
est semble)Btw, les exceptions de
.done()
ne peuvent pas être correctement détectées : en raison du modèle synchrone de.done()
, l'erreur est soit renvoyée au point de.resolve()
(peut être le code de bibliothèque!) Soit à l'.done()
appel qui attache le coupable si le différé est déjà résolu.la source
done
ne sera pas exécuté si un précédent fait a une exception. Mais pourquoi serait-il ignoré en silence, je veux dire qu'une exception s'est produite, alors pourquoi dites-vous qu'elle est silencieuse. 2) Je méprise l'Deferred
objet car son API est très très mal faite. C'est trop complexe et déroutant. Votre code ici n'aide pas non plus à prouver votre point et il a trop de complexité inutile pour ce que vous essayez de prouver. 3) Pourquoi lesdone
index at 2, 4 et 6 sont-ils exécutés avant le 2then
?.then()
seront appelés, exception (dans ces gestionnaires) levée ou non. Mais ajout /.done()
pause restante .Il existe une autre différence vitale avec jQuery 3.0 qui peut facilement conduire à un comportement inattendu et n'est pas mentionnée dans les réponses précédentes:
Considérez le code suivant:
cela produira:
Maintenant, remplacez
done()
parthen()
dans le même extrait:la sortie est maintenant:
Ainsi, pour les différés résolus immédiatement, la fonction passée à
done()
sera toujours invoquée de manière synchrone, tandis que tout argument passé àthen()
sera appelé async.Cela diffère des versions précédentes de jQuery où les deux rappels sont appelés de manière synchrone, comme mentionné dans le guide de mise à niveau :
la source
.done()
met fin à la chaîne de promesse, en s'assurant que rien d'autre ne peut attacher d'autres étapes. Cela signifie que l'implémentation de la promesse jQuery peut lever toute exception non gérée, car personne ne peut la gérer à l'aide de.fail()
.En termes pratiques, si vous ne prévoyez pas d'attacher plus d'étapes à une promesse, vous devez utiliser
.done()
. Pour plus de détails, voyez pourquoi les promesses doivent être faitesla source
.done()
n'a pas de rôle de terminaison. La documentation indique: "Puisque deferred.done () renvoie l'objet différé, d'autres méthodes de l'objet différé peuvent être chaînées à celui-ci, y compris des méthodes .done () supplémentaires"..fail()
n'est pas mentionné mais, oui, cela pourrait aussi être enchaîné.