Disons que j'ai cette fonction d'authentifier qui renvoie une promesse. La promesse se résout alors avec le résultat. Faux et vrais sont des résultats attendus, à mon avis, et les rejets ne devraient se produire que dans un cas d'erreur. Ou, un échec de l'authentification est-il considéré comme quelque chose pour lequel vous rejetteriez une promesse?
javascript
Mathieu Bertin
la source
la source
reject
et ne retournez pas faux, mais si vous attendez la valeur d'êtreBool
, alors vous étiez avec succès et vous devez résoudre avec le Bool quelle que soit la valeur. Les promesses sont en quelque sorte des procurations pour les valeurs - elles stockent la valeur renvoyée, donc seulement si la valeur n'a pas pu être obtenuereject
. Sinon, vous devriezresolve
.false
ou une levée d'exception?then
lorsque le serveur répond - même si un code d'erreur est renvoyé - et vous devez vérifier leresponse.ok
. Lecatch
gestionnaire n'est déclenché que pour les erreurs inattendues .Réponses:
Bonne question! Il n'y a pas de réponse difficile. Cela dépend de ce que vous considérez comme exceptionnel à ce point précis du flux .
Rejeter un
Promise
est le même que lever une exception. Tous les résultats indésirables ne sont pas exceptionnels , le résultat d' erreurs . Vous pouvez plaider votre cause dans les deux sens:Échec de l' authentification devrait
reject
lePromise
, parce que l'appelant attend unUser
objet en retour, et tout est bien une exception à ce flux.L'authentification échouée devrait
resolve
lePromise
, bien quenull
, puisque fournir les informations d'identification incorrectes n'est pas vraiment un cas exceptionnel , et l'appelant ne devrait pas s'attendre à ce que le flux entraîne toujours unUser
.Notez que je regarde le problème du côté de l'appelant . Dans le flux d'informations, l'appelant s'attend- il à ce que ses actions entraînent une
User
(et toute autre chose est une erreur), ou est-il logique que cet appelant particulier gère d'autres résultats?Dans un système multicouche, la réponse peut changer à mesure que les données circulent à travers les couches. Par exemple:
null
utilisateur.Cet exemple en 4 points est évidemment compliqué, mais il illustre 2 points:
Encore une fois, pas de réponse difficile. Il est temps de penser et de concevoir!
la source
Les promesses ont donc une belle propriété qu'elles apportent JS à partir des langages fonctionnels, c'est-à-dire qu'elles implémentent effectivement ce
Either
constructeur de type qui colle deux autres types, leLeft
type et leRight
type, en forçant la logique à prendre l'une ou l'autre branche branche.Maintenant, vous remarquez en effet que le type sur le côté gauche est ambigu pour les promesses; vous pouvez rejeter avec n'importe quoi. Cela est vrai car JS est faiblement typé, mais vous voulez être prudent si vous programmez de manière défensive.
La raison en est que JS prendra les
throw
instructions du code de gestion des promesses et les regroupera également dans leLeft
côté. Techniquement, dans JS, vous pouvezthrow
tout, y compris true / false ou une chaîne ou un nombre: mais le code JavaScript jette également des choses sansthrow
(lorsque vous faites des choses comme essayer d'accéder aux propriétés sur null) et il y a une API définie pour cela (l'Error
objet) . Ainsi, lorsque vous vous apprêtez à attraper, il est généralement agréable de pouvoir supposer que ces erreurs sont desError
objets. Et comme lareject
promesse s'agglomérera dans toutes les erreurs de l'un des bogues ci-dessus, vous ne voulez généralement que d'throw
autres erreurs, pour que votrecatch
déclaration ait une logique simple et cohérente.Par conséquent, bien que vous puissiez mettre un if-conditionnel dans votre
catch
et rechercher de fausses erreurs, auquel cas le cas de vérité est trivial,vous préférerez probablement la structure logique, au moins pour ce qui sort immédiatement de l'authentificateur, d'un booléen plus simple:
En fait, le prochain niveau de logique d'authentification consiste probablement à renvoyer une sorte d'
User
objet contenant l'utilisateur authentifié, de sorte que cela devienne:et c'est plus ou moins ce à quoi je m'attendrais: retour
null
dans le cas où l'utilisateur n'est pas défini, sinon retour{user_id: <number>, permission_to_launch_missiles: <boolean>}
. Je m'attendrais à ce que le cas général de ne pas être connecté soit récupérable, par exemple si nous sommes dans une sorte de mode "démo pour les nouveaux clients", et ne devrait pas être mélangé avec des bogues où j'ai accidentellement appeléobject.doStuff()
quandobject.doStuff
étaitundefined
.Maintenant que cela est dit, ce que vous voudrez peut-être faire est de définir une exception
NotLoggedIn
ouPermissionError
qui dérive deError
. Ensuite, dans les choses qui en ont vraiment besoin, vous voulez écrire:la source
les erreurs
Parlons d'erreurs.
Il existe deux types d'erreurs:
Erreurs attendues
Les erreurs attendues sont des états où la mauvaise chose se produit, mais vous savez que cela peut arriver, vous devez donc y faire face.
Ce sont des choses comme l'entrée d'utilisateur ou les demandes du serveur. Vous savez que l'utilisateur peut faire une erreur ou que le serveur est en panne, vous écrivez donc du code de vérification pour vous assurer que le programme demande à nouveau une entrée, ou affiche un message, ou tout autre comportement approprié.
Ceux-ci sont récupérables lorsqu'ils sont manipulés. S'ils ne sont pas manipulés, ils deviennent des erreurs inattendues.
Erreurs inattendues
Les erreurs inattendues (bogues) sont des états où la mauvaise chose se produit parce que le code est incorrect. Vous savez qu'ils finiront par se produire, mais il n'y a aucun moyen de savoir où ou comment les traiter car, par définition, ils sont inattendus.
Ce sont des choses comme la syntaxe et les erreurs logiques. Vous pouvez avoir une faute de frappe dans votre code, vous avez peut-être appelé une fonction avec les mauvais paramètres. Ceux-ci ne sont généralement pas récupérables.
try..catch
Parlons de
try..catch
.En JavaScript,
throw
n'est pas couramment utilisé. Si vous regardez des exemples dans le code, ils seront peu nombreux et généralement structurés dans le sens deÀ cause de ce,
try..catch
blocs ne sont pas tous communs non plus pour le flux de contrôle. Il est généralement assez facile d'ajouter quelques vérifications avant d'appeler des méthodes pour éviter les erreurs attendues.Les environnements JavaScript sont également assez indulgents, donc les erreurs inattendues sont souvent laissées non détectées également.
C # :try..catch
ne doit pas être rare. Il existe de bons cas d'utilisation, qui sont plus courants dans des langages tels que Java et C #. Java et C # ont l'avantage de tapercatch
constructions , de sorte que vous pouvez faire la différence entre les erreurs attendues et inattendues:Cet exemple permet à d'autres exceptions inattendues de remonter et d'être gérées ailleurs (par exemple en étant connecté et en fermant le programme).
En JavaScript, cette construction peut être répliquée via:
Pas aussi élégant, ce qui explique pourquoi c'est rare.
Les fonctions
Parlons des fonctions.
Si vous utilisez le principe de responsabilité unique , chaque classe et chaque fonction doivent avoir un objectif unique.
Par exemple,
authenticate()
peut authentifier un utilisateur.Cela pourrait être écrit comme suit:
Alternativement, il peut être écrit comme suit:
Les deux sont acceptables.
Promesses
Parlons de promesses.
Les promesses sont une forme asynchrone de
try..catch
. Appeleznew Promise
ouPromise.resolve
commencez votretry
code. Appelantthrow
ouPromise.reject
vous envoie lecatch
code.Si vous avez une fonction asynchrone pour authentifier un utilisateur, vous pouvez l'écrire comme:
Alternativement, il peut être écrit comme suit:
Les deux sont acceptables.
Imbrication
Parlons de l'imbrication.
try..catch
peut être imbriqué. Votreauthenticate()
méthode peut avoir en interne untry..catch
bloc tel que:De même, les promesses peuvent être imbriquées. Votre
authenticate()
méthode asynchrone peut utiliser en interne des promesses:Alors, quelle est la réponse?
Ok, je pense qu'il est temps pour moi de répondre à la question:
La réponse la plus simple que je puisse donner est que vous devriez rejeter une promesse partout où vous voudriez autrement
throw
une exception s'il s'agissait d'un code synchrone.Si votre flux de contrôle est plus simple en ayant quelques
if
vérifications dans vosthen
relevés, il n'est pas nécessaire de rejeter une promesse.Si votre flux de contrôle est plus simple en rejetant une promesse puis en vérifiant les types d'erreurs dans votre code de gestion des erreurs, faites-le à la place.
la source
J'ai utilisé la branche "rejeter" d'une promesse pour représenter l'action "annuler" des boîtes de dialogue de l'interface utilisateur jQuery. Cela semblait plus naturel que d'utiliser la branche "résoudre", notamment parce qu'il y a souvent plusieurs options "fermer" dans une boîte de dialogue.
la source
Gérer une promesse est plus ou moins comme une condition «si». C'est à vous de décider si vous voulez "résoudre" ou "rejeter" si l'authentification a échoué.
la source
try..catch
, nonif
.try...catch
et simplement dire que si vous avez pu terminer et obtenir un résultat, vous devez résoudre quelle que soit la valeur reçue, sinon vous devriez rejeter?try { if (!doSomething()) throw whatever; doSomethingElse() } catch { ... }
est parfaitement bien, mais la construction quePromise
représente un est latry..catch
partie, pas laif
partie.doSomething()
échoue, alors il lancera, mais sinon il pourrait contenir la valeur dont vous avez besoin (votreif
ci-dessus est légèrement déroutant car cela ne fait pas partie de votre idée ici :)). Vous ne devez rejeter que s'il y a une raison de lancer (dans l'analogie), donc si le test a échoué. Si le test a réussi, vous devez toujours le résoudre, que sa valeur soit positive, non?