Je lisais des articles sur les reports et les promesses de jQuery et je ne vois pas la différence entre utiliser .then()
& .done()
pour des rappels réussis. Je sais que Eric Hynds mentionne que .done()
et .success()
correspondent à la même fonctionnalité, mais je suppose que .then()
est identique à tous les rappels invoqués achèvement d'une opération réussie.
Quelqu'un peut-il s'il vous plaît m'éclairer à l'utilisation correcte?
Les rappels attachés à done()
seront déclenchés lorsque le différé sera résolu. Les rappels attachés à fail()
seront déclenchés lorsque le différé est rejeté.
Avant jQuery 1.8, then()
n'était qu'un sucre syntaxique:
promise.then( doneCallback, failCallback )
// was equivalent to
promise.done( doneCallback ).fail( failCallback )
À partir de la version 1.8, then()
est un alias pour pipe()
et renvoie une nouvelle promesse, voir ici pour plus d'informations sur pipe()
.
success()
et error()
ne sont disponibles que sur l'objet jqXHR
renvoyé par un appel à ajax()
. Ce sont de simples alias pour done()
et fail()
respectivement:
jqXHR.done === jqXHR.success
jqXHR.fail === jqXHR.error
De plus, done()
ne se limite pas à un seul rappel et filtrera les non-fonctions (bien qu'un bogue avec les chaînes dans la version 1.8 soit corrigé dans la version 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 );
Il en va de même pour fail()
.
Il existe également une différence dans la manière dont les résultats de retour sont traités (son chaînage appelé, done
ne chaîne pas tandis que then
produit des chaînes d’appel)
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)
})
Les résultats suivants seront enregistrés:
abc
123
undefined
Tandis que
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)
})
obtiendra le suivant:
abc
abc
abc
---------- Mise à jour:
Btw. J'ai oublié de mentionner que si vous retournez une promesse au lieu d'une valeur de type atomique, la promesse extérieure attendra que la promesse intérieure se résolve:
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 cette manière, il devient très simple de composer des opérations asynchrones parallèles ou séquentielles telles que:
// 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
})
Le code ci-dessus émet deux requêtes http en parallèle, ce qui permet de les traiter plus rapidement, tandis que les requêtes ci-dessous sont exécutées de manière séquentielle, réduisant ainsi la charge du serveur
// 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()
a un seul rappel et c'est le rappel de succès
.then()
a des rappels avec succès et échecs
.fail()
n'a qu'un seul rappel d'échec
vous avez donc la responsabilité de ce que vous devez faire ... cela vous importe-t-il que cela réussisse ou non?
ajoute des gestionnaires à appeler niquement lorsque le différé est résol. Vous pouvez ajouter plusieurs rappels à appeler.
var url = 'http://jsonplaceholder.typicode.com/posts/1';
$.ajax(url).done(doneCallback);
function doneCallback(result) {
console.log('Result 1 ' + result);
}
Vous pouvez aussi écrire ci-dessus comme ça,
function ajaxCall() {
var url = 'http://jsonplaceholder.typicode.com/posts/1';
return $.ajax(url);
}
$.when(ajaxCall()).then(doneCallback, failCallback);
ajoute des gestionnaires à appeler lorsque Deferred est résolu, rejeté ou toujours en cours.
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);
}
Il y a en fait une différence assez critique, dans la mesure où jQuery's Deferreds est censé être une implémentation de Promises (et jQuery3.0 tente en fait de les intégrer dans les spécifications).
La principale différence entre done/then est que
.done()
TOUJOURS renvoie les mêmes valeurs Promise/enveloppé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 responsable de contrôler ce que cette promesse est basée sur ce que la fonction que vous avez transmise est retournée.Traduit de jQuery en promesses ES2015 natives, .done()
revient à implémenter une structure "tap" autour d'une fonction dans une chaîne Promise, en ce sens que si la chaîne est dans l'état "résoudre", une valeur est transmise. à une fonction ... mais le résultat de cette fonction n'affectera PAS la chaîne elle-même.
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));
Ceux-ci consigneront 5, pas 6.
Notez que j'ai utilisé done et doneWrap pour faire la journalisation, pas .then. En effet, les fonctions console.log ne renvoient rien. Et que se passe-t-il si vous passez une fonction qui ne retourne rien?
Promise.resolve(5)
.then(doneWrap( x => x + 1))
.then(console.log.bind(console))
.then(console.log.bind(console));
Cela va enregistrer:
5
undefined
Qu'est-il arrivé? Quand j'ai utilisé .then et lui avons passé une fonction qui ne renvoyait rien, le résultat implicite était "indéfini" ... ce qui, bien sûr, renvoyait une promesse [indéfinie] à la méthode suivante, qui enregistrait indéfini. Donc, la valeur initiale avec laquelle nous avons commencé était pratiquement perdue.
.then()
est, au fond, une forme de composition de fonctions: le résultat de chaque étape est utilisé comme argument de la fonction dans l'étape suivante. C’est la raison pour laquelle .done est mieux considéré comme un "tap" -> il ne fait pas partie de la composition, mais donne un aperçu de la valeur à un certain stade 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 de méthode .done implémentée. Nous n’avons pas besoin d’expliquer pourquoi il n’existe pas de méthode .fail, car c’est encore plus compliqué (à savoir, .fail/.catch ne sont PAS des miroirs de .done/.then -> les fonctions dans .catch qui renvoient des valeurs nues ne "rester" rejeté comme ceux passés à .alors, ils résolvent!)
then()
signifie toujours qu'il sera appelé dans n'importe quel cas. Mais les paramètres transmis 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()
renvoie une nouvelle promesse. Si elle renvoie une valeur, elle sera transmise à la fonction de rappel suivante.
Voyons l'exemple suivant:
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 );
Avant jQuery 1.8, la réponse devrait être
result = 3
result = 3
result = 3
Tout result
prend 3. Et then()
fonction passe toujours le même objet différé à la fonction suivante.
Mais à partir de jQuery 1.8, le résultat devrait être:
result = 3
result = 7
result = NaN
Parce que la première fonction then()
renvoie une nouvelle promesse et que la valeur 7 (et qu’il s’agit du seul paramètre qui sera transmis) est transmise à la prochaine done()
, de sorte que la seconde done()
write result = 7
. La seconde then()
prend 7 comme valeur de a
et undefined
en tant que valeur de b
de sorte que la seconde then()
renvoie une nouvelle promesse avec le paramètre NaN et le dernier done()
imprime NaN comme résultat.
Il existe une très simple cartographie mentale dans la réponse qui était un peu difficile à trouver dans les autres réponses:
done
implémente tap
comme dans Bluebird Promises
then
implémente then
comme dans ES6 Promises