Les actions telles que l'appel d'une API ou la validation des données saisies par l'utilisateur sont très courantes en développement et sont des exemples de fonctions qui peuvent donner un résultat correct ou échouer. Généralement, pour le contrôler en javascript (et dans d'autres langages), nous utilisons et créons généralement des exceptions simples.
Ils semblent être le moyen le plus simple de contrôler les erreurs que peut contenir l'application ou le programme que nous développons. Cependant, à mesure que les projets et les équipes se développent, des scénarios commencent à émerger qui exigent quelque chose de plus de notre part. Dans les grandes équipes, par exemple, il est très utile que les fonctions soient explicites lorsqu'elles indiquent si elles peuvent échouer, afin de permettre à nos collègues d'anticiper et de gérer ces erreurs.
Être explicite sur les types d'"erreurs" qu'une action peut provoquer ne contribuera pas seulement à rendre le développement beaucoup plus facile. Il servira également de documentation des règles métier.
En javascript, nous disposons de quelques techniques pour y parvenir. Pour aller au-delà de la théorie, prenons un exemple concret : dans une application de réservation d'hôtel, un utilisateur réserve une chambre, reçoit un code, puis doit payer pour cela. Lors du paiement, l'API peut actuellement nous montrer ces 3 scénarios "d'erreur" :
El código de reserva no existe. El pago es rechazado. El código de reserva ya no es válido.
Comme nous réalisons une demande pour l'utilisateur, en plus de ces deux cas, vous devez en prendre en compte un supplémentaire :
No hay conexión a internet. (o el servicio no esta disponible)
Cette fonction peut être appelée depuis différents composants de notre application et si elle échoue, l'erreur doit être affichée à l'utilisateur.
En gardant cet exemple à l'esprit, passons en revue quelques possibilités sur la façon de le gérer
Les exceptions sont courantes dans de nombreux langages, et JavaScript en inclut certaines prédéfinies (comme SyntaxError). Face à d'éventuelles erreurs, une bonne pratique consiste à être précis et à les personnaliser.
En js pour créer une exception, utilisez simplement le mot réservé throw suivi de ce que nous voulons (si c'est ainsi que vous le lisez).
function makeError() { throw "Error string" }
Js est très permissif en ce sens, mais il est considéré comme une mauvaise pratique de lancer quelque chose qui ne descend pas de la classe Error fournie dans js.
class MyError extends Error { constructor(message) { super(message); this.name = "MyError"; } } function makeError() { throw MyError("") }
Comme vous pouvez le voir, la classe d'erreur est livrée avec une propriété qui nous permet de décrire plus en détail pourquoi nous créons l'exception (et nous pouvons ajouter les propriétés que nous souhaitons).
Revenant au problème que nous avons posé en exemple. En appliquant des erreurs personnalisées, nous pouvons contrôler ce qu'il faut faire dans chaque scénario.
El código de reserva no existe. El pago es rechazado. El código de reserva ya no es válido.
Avec cela, nous obtenons non seulement le pouvoir d'acheminer le flux de différentes manières, mais nous distinguons également les erreurs internes du système (par exemple l'erreur d'une dépendance interne que nous utilisons dans payReservation, etc.) de ce qui représente les règles métier. .
C'est une très bonne option, et elle répond à notre objectif de contrôler le flux en fonction de chaque cas et si quelqu'un voit la fonction, il sait pourquoi elle peut échouer. Avec cela, nous gagnons déjà beaucoup, mais il y a certaines choses que nous devons considérer avec cette approche.
Les exceptions d'une fonction si elles ne sont pas contrôlées au sein d'un catch passent au "niveau supérieur". Pour donner un exemple, si vous avez la fonction A, qui appelle B, celle-ci appelle à son tour C et C lève une exception . contrôlé cela ira à B, si B ne le contrôle pas alors il continue jusqu'à A etc. Selon votre cas, cela peut être une bonne nouvelle. Déclarer une éventuelle erreur par règle métier pourrait s'avérer fastidieux, puisqu'il faudrait revoir toutes les fonctions pour d'éventuelles exceptions.
Un autre point à prendre en compte est l'expiration du développeur tant valorisée aujourd'hui. Bien que des outils comme JsDoc permettent de décrire en ajoutant qu'une méthode peut avoir une exception, l'éditeur ne la reconnaît pas. En revanche, Typescript ne reconnaît pas ces exceptions lors de l'écriture ou de l'appel de la fonction.
[] **Performances :* le lancement et la gestion des exceptions ont un impact (minime) sur les performances (similaire à l'utilisation de break). Bien que dans des environnements comme une application, cet impact soit presque nul.
Si l'on regarde le cas précédent, les exceptions que nous créons ne sont pas dues à des erreurs "irréparables", mais font plutôt partie des règles métier. Lorsque les exceptions deviennent courantes, elles cessent d’être des cas réellement exceptionnels et ont été conçues pour cela. Au lieu de lever des exceptions, nous pouvons encapsuler les statuts « succès » et « erreur » dans un seul objet comme celui-ci.
No hay conexión a internet. (o el servicio no esta disponible)
Si nous utilisons typescript (ou d.ts pour utiliser jsdoc) nous pourrions définir les types comme ceci.
function makeError() { throw "Error string" }
L'appliquer à notre exemple. Si maintenant notre fonction payReservation renvoie cet objet au lieu d'une exception, en utilisant JSDoc ou Typescript nous pouvons spécifier quel type de résultats nous pouvons prendre (à partir de maintenant je mettrai les exemples en dactylographié pour plus de simplicité).
Cela aide l'équipe à savoir à l'avance quelles erreurs la fonction peut renvoyer.
class MyError extends Error { constructor(message) { super(message); this.name = "MyError"; } } function makeError() { throw MyError("") }
En appliquant cela, nous obtenons les avantages de l'approche avec exceptions et aussi, au moment du développement, l'éditeur affichera des informations sur les différents cas "d'erreur" qui peuvent survenir.
En fait, ce type de concept existe depuis longtemps en programmation, dans de nombreux langages fonctionnels ils n'ont pas d'exceptions et ils utilisent ce type de données pour leur erreur, aujourd'hui de nombreux langages l'implémentent. Dans Rust et Dart par exemple, la classe Result existe nativement, la bibliothèque Arrow de Kotlin l'ajoute également.
Il existe une certaine norme sur la façon d'utiliser et d'implémenter le résultat, afin que notre code soit plus compréhensible pour les nouveaux développeurs, nous pouvons nous appuyer sur ces conventions.
Le résultat peut représenter exclusivement un état de réussite ou d'erreur (il ne peut pas s'agir des deux en même temps) et permet de travailler avec les deux états sans lever d'exceptions.
El código de reserva no existe. El pago es rechazado. El código de reserva ya no es válido.
L'exemple utilise des classes mais ce n'est pas nécessaire, il existe aussi des implémentations plus simples, j'en ai une que j'emporte habituellement dans des projets où je pense que je pourrais en avoir besoin, je laisse le lien au cas où vous voudriez le voir et/ou utilisez-le.
Si on laisse comme ça, on ne gagne pas grand chose par rapport à l'objet qu'on a créé auparavant. C'est pourquoi il est bon de savoir qu'il implémente généralement plus de méthodes
Par exemple une méthode getOrElse pour renvoyer les valeurs par défaut en cas d'erreur.
No hay conexión a internet. (o el servicio no esta disponible)
et pliez-vous pour gérer fonctionnellement le flux de réussite/échec.
function makeError() { throw "Error string" }
Vous pouvez également trouver des informations sur la gestion des erreurs en utilisant l'un ou l'autre. Le résultat serait un Soit avec un plus grand contexte, Soit a la valeur droite (droite) et gauche (gauche). Comme en anglais right est aussi utilisé pour dire que quelque chose est juste, il a généralement la valeur correcte alors que l'erreur est à gauche, mais ce n'est pas forcément le cas, le résultat est plutôt plus explicite par rapport à où c'est la valeur correcte et l'erreur.
En l'appliquant à notre exemple, payReservation ressemblerait à ceci :
class MyError extends Error { constructor(message) { super(message); this.name = "MyError"; } } function makeError() { throw MyError("") }
[*] Une bonne pratique serait d'établir un type de données de base pour les erreurs, dans l'exemple, utilisez une chaîne, mais idéalement, il aurait une forme plus définie telle qu'un objet nommé auquel plus de données peuvent être ajoutées. Par exemple, vous pouvez voir un exemple ici
À première vue, il peut sembler que l'ajout de la classe relève plus de l'ingénierie excessive qu'autre chose. Mais Result est un concept largement utilisé, le maintien des conventions aide votre équipe à le détecter plus rapidement et constitue un moyen efficace de renforcer votre gestion des erreurs.
Avec cette option nous décrivons explicitement quelles "erreurs" une fonction peut avoir, nous pouvons contrôler le flux de notre application en fonction du type d'erreur, nous obtenons de l'aide de l'éditeur lors de l'appel de la fonction et enfin nous laissons des exceptions pour erreur cas dans le système.
Malgré ces avantages, certains points doivent également être pris en considération avant de le mettre en œuvre. Comme je l'ai mentionné au début de cette section, Result est natif dans de nombreux langages mais pas en JS, donc en l'implémentant nous ajoutons une abstraction supplémentaire. Un autre point à prendre en compte est le scénario dans lequel nous nous trouvons, toutes les applications n'auront pas besoin d'autant de contrôle (Sur une landing page d'une campagne publicitaire par exemple, je ne verrais pas l'intérêt de mettre en place le Résultat). Cela vaut la peine d'évaluer si vous pouvez profiter de tout le potentiel ou si ce sera simplement un poids supplémentaire.
En bref, la gestion des erreurs améliore non seulement la qualité du code mais également la collaboration en équipe en fournissant un flux de travail prévisible et bien documenté. Les résultats et les exceptions personnalisées sont des outils qui, bien utilisés, contribuent à un code plus maintenable et plus robuste.
Dans TypeScript, nous pouvons tirer un avantage supplémentaire de Result pour garantir que tous les cas d'erreur sont couverts :
El código de reserva no existe. El pago es rechazado. El código de reserva ya no es válido.
La fonction typeCheck a pour objectif de valider que toutes les valeurs possibles de e sont vérifiées dans le if/else if.
Dans ce dépôt, je laisse un peu plus de détails.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!