Quand dois-je utiliser la méthode «then» de jQuery deferred et quand dois-je utiliser la méthode «pipe»?

jQuery’s Deferred a deux fonctions qui peuvent être utilisées pour implémenter le chaînage asynchrone des fonctions:

then()

deferred.then( doneCallbacks, failCallbacks ) Returns: Deferred

doneCallbacks Fonction ou tableau de fonctions appelé lorsque le différé est résolu.
failCallbacks Une fonction ou un tableau de fonctions appelé lorsque le différé est rejeté.

pipe()

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

doneFilter Fonction facultative appelée lorsque le différé est résolu.
failFilter Une fonction facultative appelée lorsque le différé est rejeté.

Je sais then() a été un peu plus long que pipe() alors ce dernier doit append un avantage supplémentaire, mais quelle est la différence précisément qui m’échappe. Les deux prennent à peu près les mêmes parameters de rappel, bien qu’ils diffèrent par leur nom, et la différence entre le retour d’un Deferred et le retour d’une Promise semble faible.

J’ai lu les docs officiels encore et encore, mais je les trouve toujours trop “denses” pour bien comprendre et la recherche a trouvé beaucoup de discussions sur l’une ou l’autre caractéristique mais je n’ai rien trouvé qui clarifie vraiment les différences. avantages et inconvénients de chacun.

Alors, quand est-il préférable d’utiliser then et quand est-il préférable d’utiliser le pipe ?


Une addition

L’excellente réponse de Felix a vraiment aidé à clarifier la différence entre ces deux fonctions. Mais je me demande s’il y a des moments où la fonctionnalité de then() est préférable à celle de pipe() .

Il est évident que pipe() est plus puissant qu’alors then() et il semble que le premier puisse faire tout ce que ce dernier peut faire. Une des raisons d’utiliser then() pourrait être que son nom reflète son rôle en tant que terminaison d’une chaîne de fonctions traitant les mêmes données.

Mais y a-t-il un cas d’utilisation qui nécessite que then() retourne l’original Deferred qui ne peut pas être fait avec pipe() parce qu’il renvoie une nouvelle Promise ?

Depuis que jQuery 1.8 .then se comporte comme .pipe :

Avis de déchéance: à partir de jQuery 1.8, la méthode deferred.pipe() est obsolète. La méthode deferred.then() , qui la remplace, devrait être utilisée à la place.

et

À partir de jQuery 1.8 , la méthode deferred.then() renvoie une nouvelle promesse qui peut filtrer le statut et les valeurs d’un différé via une fonction, remplaçant la méthode maintenant deferred.pipe() .

Les exemples ci-dessous pourraient encore être utiles à certains.


Ils servent à des fins différentes:

  • .then() doit être utilisé chaque fois que vous souhaitez travailler avec le résultat du processus, c’est-à-dire comme le dit la documentation, lorsque l’object différé est résolu ou rejeté. C’est la même chose que d’utiliser .done() ou .fail() .

  • Vous utiliseriez .pipe() pour (pré) filtrer le résultat. La valeur de retour d’un rappel à .pipe() sera transmise en tant qu’argument aux callbacks done et fail . Il peut également renvoyer un autre object différé et les rappels suivants seront enregistrés sur ce différé.

    Ce n’est pas le cas avec .then() (ou .done() , .fail() ), les valeurs de retour des rappels enregistrés sont simplement ignorées.

Donc, ce n’est pas que vous utilisez soit .then() ou .pipe() . Vous pouvez utiliser .pipe() aux mêmes fins que .then() mais l’inverse n’est pas possible.


Exemple 1

Le résultat d’une opération est un tableau d’objects:

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

et vous voulez calculer le minimum et le maximum des valeurs. Supposons que nous utilisons deux rappels 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" */ }); 

Dans les deux cas, vous devez parcourir la liste et extraire la valeur de chaque object.

Ne serait-il pas préférable d'extraire les valeurs à l'avance pour ne pas avoir à le faire individuellement dans les deux callbacks? Oui! Et c'est ce que nous pouvons utiliser .pipe() pour:

 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" */ }); 

Evidemment, c'est un exemple inventé et il y a beaucoup de façons différentes (peut-être meilleures) de résoudre ce problème, mais j'espère que cela illustre bien ce point.


Exemple 2

Considérez les appels Ajax. Parfois, vous souhaitez lancer un appel Ajax après la fin d'un précédent. Une des manières est de faire le deuxième appel dans un callback done :

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

Supposons maintenant que vous souhaitiez découpler votre code et placer ces deux appels Ajax dans une fonction:

 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 }); }); } 

Vous souhaitez utiliser l'object différé pour autoriser un autre code qui appelle makeCalls à joindre des rappels pour le deuxième appel Ajax, mais

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

n'aurait pas l'effet désiré car le deuxième appel est effectué dans un rappel done et n'est pas accessible de l'extérieur.

La solution serait d'utiliser .pipe() place:

 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 }); 

En utilisant .pipe() vous pouvez désormais append des rappels à l'appel Ajax "interne" sans exposer le stream / ordre réel des appels.


En général, les objects différés constituent un moyen intéressant de découpler votre code 🙂

Il n’y a pas de cas où vous DEVEZ utiliser then() sur pipe() . Vous pouvez toujours choisir d’ignorer la valeur que passera pipe() . Il peut y avoir une légère baisse de performance pour l’utilisation de pipe – mais il est peu probable que cela ait de l’importance.

Donc, il peut sembler que vous puissiez toujours utiliser pipe() dans les deux cas. Cependant , en utilisant pipe() , vous communiquez à d’autres personnes lisant votre code (y compris vous-même, dans six mois à partir de maintenant) qu’il existe une certaine importance pour la valeur de retour. Si vous le jetez, vous violez cette construction sémantique.

C’est comme avoir une fonction qui retourne une valeur qui n’est jamais utilisée: confus.

Donc, utilisez then() quand vous devriez, et pipe() quand vous devriez …

En fait, il s’avère que la différence entre .then() et .pipe() a été jugée inutile et ils ont été faits pour être les mêmes que ceux de la version 1.8 de jQuery.

D’après un commentaire de jaubourg dans le ticket de suivi des bogues de jQuery # 11010 “MAKE DEFERRED.THEN == DEFERRED.PIPE LIKE PROMISE / A”:

En 1.8, nous supprimerons l’ancien puis le remplacerons par le tuyau actuel. Mais la conséquence très sortingste est que nous devrons dire aux gens d’utiliser le non-standard fait, échouer et progresser, car la proposition ne fournit pas de simple, EFFICACE, signifie simplement append un rappel.

(emphassis mine)