Je suis encore assez nouveau dans les promesses et j'utilise actuellement bluebird, mais j'ai un scénario où je ne sais pas trop comment y faire face.
Donc, par exemple, j'ai une chaîne de promesses dans une application express comme ceci:
repository.Query(getAccountByIdQuery)
.catch(function(error){
res.status(404).send({ error: "No account found with this Id" });
})
.then(convertDocumentToModel)
.then(verifyOldPassword)
.catch(function(error) {
res.status(406).send({ OldPassword: error });
})
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
Donc, le comportement que je recherche est:
- Va pour obtenir un compte par ID
- S'il y a un rejet à ce stade, bombardez et renvoyez une erreur
- S'il n'y a pas d'erreur, convertissez le document renvoyé en modèle
- Vérifiez le mot de passe avec le document de base de données
- Si les mots de passe ne correspondent pas, bombardez et renvoyez une erreur différente
- S'il n'y a pas d'erreur, changez les mots de passe
- Puis retourne le succès
- Si quelque chose ne va pas, retournez un 500
Donc, actuellement, les captures ne semblent pas arrêter le chaînage, et cela a du sens, alors je me demande s'il existe un moyen pour moi de forcer d'une manière ou d'une autre la chaîne à s'arrêter à un certain point en fonction des erreurs, ou s'il existe un meilleur moyen. pour structurer cela pour obtenir une forme de comportement de branchement, comme dans le cas de if X do Y else Z
.
Toute aide est la bienvenue.
javascript
node.js
promise
bluebird
Grofit
la source
la source
Réponses:
Ce comportement est exactement comme un lancer synchrone:
C'est la moitié de l'intérêt de
.catch
- être en mesure de récupérer des erreurs. Il peut être souhaitable de renvoyer pour signaler que l'état est toujours une erreur:Cependant, cela seul ne fonctionnera pas dans votre cas car l'erreur sera interceptée par un gestionnaire ultérieur. Le vrai problème ici est que les gestionnaires d'erreurs généralisés «GÉRER TOUT» sont une mauvaise pratique en général et sont extrêmement mal vus dans d'autres langages de programmation et écosystèmes. Pour cette raison, Bluebird propose des captures typées et prédicat.
L'avantage supplémentaire est que votre logique métier n'a pas (et ne devrait pas) avoir à connaître du tout le cycle de demande / réponse. Il n'est pas de la responsabilité de la requête de décider quel état HTTP et quelle erreur le client obtient et plus tard, à mesure que votre application se développe, vous souhaiterez peut-être séparer la logique métier (comment interroger votre base de données et comment traiter vos données) de ce que vous envoyez au client. (quel code d'état http, quel texte et quelle réponse).
Voici comment j'écrirais votre code.
Tout d'abord, je pourrais
.Query
lancer unNoSuchAccountError
, je le sous-classePromise.OperationalError
que Bluebird fournit déjà. Si vous ne savez pas comment sous-classer une erreur, faites-le moi savoir.Je le sous-classerais également pour
AuthenticationError
puis ferais quelque chose comme:Comme vous pouvez le voir - c'est très propre et vous pouvez lire le texte comme un manuel d'instructions de ce qui se passe dans le processus. Il est également séparé de la demande / réponse.
Maintenant, je l'appellerais à partir du gestionnaire d'itinéraire en tant que tel:
De cette façon, la logique est au même endroit et la décision sur la manière de gérer les erreurs pour le client est au même endroit et elles ne s'encombrent pas.
la source
.catch(someSpecificError)
gestionnaire intermédiaire pour une erreur spécifique est que si vous voulez attraper un type d'erreur spécifique (qui est inoffensif), traitez-le et continuez le flux qui suit. Par exemple, j'ai un code de démarrage qui a une séquence de choses à faire. La première chose est de lire le fichier de configuration à partir du disque, mais si ce fichier de configuration est manquant, c'est une erreur OK (le programme a intégré les valeurs par défaut) afin que je puisse gérer cette erreur spécifique et continuer le reste du flux. Il peut également être préférable de ne pas partir avant plus tard.instanceof
chceks manuellement vous-même..catch
fonctionne comme l'try-catch
instruction, ce qui signifie que vous n'avez besoin que d'une seule prise à la fin:la source
Non. Vous ne pouvez pas vraiment "terminer" une chaîne, sauf si vous lancez une exception qui bouillonne jusqu'à sa fin. Voir la réponse de Benjamin Gruenbaum pour savoir comment procéder.
Une dérivation de son modèle serait de ne pas distinguer les types d'erreur, mais d'utiliser les erreurs qui ont
statusCode
et lesbody
champs qui peuvent être envoyés à partir d'un seul.catch
gestionnaire générique . En fonction de la structure de votre application, sa solution pourrait être plus propre.Oui, vous pouvez faire des branches avec des promesses . Cependant, cela signifie quitter la chaîne et "revenir" à l'imbrication - comme vous le feriez dans une instruction if-else ou try-catch imbriquée:
la source
J'ai fait de cette façon:
Vous laissez votre prise à la fin. Et lancez simplement une erreur quand cela se produit au milieu de votre chaîne.
Vos autres fonctions ressembleraient probablement à ceci:
la source
Probablement un peu tard à la fête, mais il est possible de nicher
.catch
comme indiqué ici:Mozilla Developer Network - Utilisation des promesses
Edit: J'ai soumis ceci car il fournit la fonctionnalité demandée en général. Cependant, ce n'est pas le cas dans ce cas particulier. Parce que, comme expliqué en détail par d'autres déjà,
.catch
est censé récupérer l'erreur. Vous ne pouvez pas, par exemple, envoyer une réponse au client dans plusieurs.catch
rappels car un.catch
sans explicite lereturn
résout avecundefined
dans ce cas, provoquant le.then
déclenchement même si votre chaîne n'est pas vraiment résolue, provoquant potentiellement le.catch
déclenchement et l'envoi d' un suivi une autre réponse au client, provoquant une erreur et vous jetant probablement unUnhandledPromiseRejection
chemin. J'espère que cette phrase alambiquée vous a donné du sens.la source
Au lieu de
.then().catch()...
vous pouvez le faire.then(resolveFunc, rejectFunc)
. Cette chaîne de promesses serait meilleure si vous gérez les choses en cours de route. Voici comment je le réécrirais:Remarque: le
if (error != null)
est un peu un hack pour interagir avec l'erreur la plus récente.la source
Je pense que la réponse de Benjamin Gruenbaum ci - dessus est la meilleure solution pour une séquence logique complexe, mais voici mon alternative pour les situations plus simples. Je viens d' utiliser un
errorEncountered
drapeau avecreturn Promise.reject()
sauter toute modification ultérieurethen
oucatch
déclarations. Cela ressemblerait donc à ceci:Si vous avez plus de deux paires then / catch, vous devriez probablement utiliser la solution de Benjamin Gruenbaum. Mais cela fonctionne pour une configuration simple.
Notez que la finale a
catch
seulementreturn;
plutôt quereturn Promise.reject();
, car il n'y a pas de suitethen
que nous devons ignorer, et cela compterait comme un rejet de promesse non géré, ce que Node n'aime pas. Comme il est écrit ci-dessus, la finalecatch
renverra une promesse résolue pacifiquement.la source