web-dev-qa-db-fra.com

Quand est-ce que. Puis (succès, échec) est considéré comme un anti-modèle pour les promesses?

J'ai jeté un œil à la promesse de bluebird FAQ , dans laquelle il est mentionné que .then(success, fail) est un antipattern . Je ne comprends pas très bien son explication quant à l’essai et à la capture. Quel est le problème avec ce qui suit?

some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })

Il semble que l'exemple suggère ce qui suit correctement.

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

Quelle est la différence?

145
user2127480

Quelle est la différence?

L'appel .then() renverra une promesse qui sera rejetée au cas où le rappel renverrait une erreur. Cela signifie que lorsque votre succès logger échoue, l'erreur est transmise au rappel .catch() suivant, mais pas au rappel fail qui accompagne success.

Voici un diagramme flux de contrôle:

control flow diagram of then with two argumentscontrol flow diagram of then catch chain

Pour l'exprimer en code synchrone:

// some_promise_call().then(logger.log, logger.log)
then: {
    try {
        var results = some_call();
    } catch(e) {
        logger.log(e);
        break then;
    } // else
        logger.log(results);
}

La seconde log (qui ressemble au premier argument de .then()) ne sera exécutée que dans le cas où aucune exception ne se produirait. Le bloc libellé et l'instruction break semblent un peu bizarres, c'est en fait ce que python a try-except-else pour (lecture recommandée!).

// some_promise_call().then(logger.log).catch(logger.log)
try {
    var results = some_call();
    logger.log(results);
} catch(e) {
    logger.log(e);
}

L'enregistreur catch gérera également les exceptions de l'appel de l'enregistreur de succès.

Voilà pour la différence.

Je ne comprends pas très bien son explication quant à l'essayer et attraper

L'argument est que vous voulez généralement capturer les erreurs à chaque étape du traitement et que vous ne devriez pas l'utiliser dans les chaînes. On s'attend à ce que vous ne disposiez que d'un dernier gestionnaire gérant toutes les erreurs - tandis que, lorsque vous utilisez "l'antipattern", les erreurs de certains rappels ne sont pas gérées.

Cependant, ce modèle est en réalité très utile: lorsque vous voulez gérer les erreurs qui se sont produites exactement à cette étape et que vous voulez faire quelque chose entièrement différent lorsqu'aucune erreur ne s’est produite - c’est-à-dire lorsque l’erreur est irrécupérable. Soyez conscient qu'il s'agit de branchement votre flux de contrôle. Bien sûr, cela est parfois souhaité.


Quel est le problème avec ce qui suit?

some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })

Que vous deviez répéter votre rappel. Tu veux plutôt

some_promise_call()
   .catch(function(e) {
       return e; // it's OK, we'll just log it
   })
   .done(function(res) {
       logger.log(res);
   });

Vous pouvez également envisager d’utiliser .finally() pour cela.

172
Bergi

Les deux ne sont pas tout à fait identiques. La différence est que le premier exemple n'interceptera pas une exception émise dans votre gestionnaire success. Ainsi, si votre méthode ne doit jamais renvoyer que des promesses résolues, comme c'est souvent le cas, vous avez besoin d'un gestionnaire de fin catch (ou encore d'un autre then avec un paramètre vide success). Bien sûr, il se peut que votre gestionnaire then ne fasse rien qui puisse potentiellement échouer. Dans ce cas, utiliser un then à 2 paramètres pourrait convenir.

Mais je crois que l’intérêt du texte que vous avez lié est que then est surtout utile par rapport aux rappels en raison de sa capacité à enchaîner plusieurs étapes asynchrones, et lorsque vous le faites réellement, la forme à deux paramètres de then ne se comporte pas assez bien comme prévu, pour la raison ci-dessus. C'est particulièrement contre-intuitif lorsqu'il est utilisé en milieu de chaîne.

En tant que personne qui a fait beaucoup de choses complexes asynchrones et s'est heurtée à des virages comme celui-ci plus que je tiens à l'admettre, je recommande vraiment d'éviter cet anti-modèle et de suivre l'approche du gestionnaire séparé.

30
acjay

En examinant les avantages et les inconvénients des deux, nous pouvons deviner ce qui convient le mieux à la situation. Ce sont les deux principales approches pour la mise en œuvre des promesses. Les deux ont des avantages et des inconvénients 

Approche de capture

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

Avantages

  1. Toutes les erreurs sont gérées par un seul bloc catch.
  2. Même attrape toute exception dans le bloc d'alors.
  3. Chaînage de rappels de succès multiples

Désavantages

  1. En cas de chaînage, il devient difficile d'afficher des messages d'erreur différents.

Approche succès/erreur

some_promise_call()
.then(function success(res) { logger.log(res) },
      function error(err) { logger.log(err) })

Avantages

  1. Vous obtenez un contrôle d'erreur très précis.
  2. Vous pouvez avoir une fonction commune de traitement des erreurs pour différentes catégories d’erreurs telles que les erreurs de base de données, les erreurs 500, etc. 

Désavantages

  1. Vous aurez toujours besoin d'une autre catch si vous souhaitez gérer les erreurs renvoyées par le rappel de réussite.
14
aWebDeveloper

Simple expliquer:

Dans ES2018

Lorsque la méthode catch est appelée avec l'argument onRejected, le fichier les étapes suivantes sont prises:

  1. Laisser la promesse être la cette valeur.
  2. Revenir ? Invoke (promesse, "puis", "indéfini, surRejecté").

cela signifie:

promise.then(f1).catch(f2)

équivaut à

promise.then(f1).then(undefiend, f2)
0
saltfish

Utiliser .then().catch() vous permet d'activer le chaînage des promesses qui est nécessaire pour exécuter un flux de travail. Vous devrez peut-être lire certaines informations de la base de données pour ensuite les transmettre à une API asynchrone, puis manipuler la réponse. Vous souhaiterez peut-être repousser la réponse dans la base de données. Traiter tous ces flux de travail avec votre concept est faisable mais très difficile à gérer. La meilleure solution sera then().then().then().then().catch() qui reçoit toutes les erreurs en une seule fois et vous permet de conserver la maintenabilité du code.

0
Jayant Varshney