lorsque nous développons quelque chose, nous avons souvent besoin de nos propres classes d’erreurs pour refléter des choses spécifiques qui peuvent mal tourner dans nos tâches. Pour les erreurs dans les opérations de réseau, nous pouvons avoir besoin HttpError
, pour les opérations de base de données DbError
, pour la recherche d’opérations NotFoundError
et ainsi de suite.
Nos erreurs devraient soutenir erreur de base de propriétés comme la message
, name
et, de préférence, stack
. Mais ils peuvent aussi avoir d’autres propriétés qui leur sont propres, par exemple, HttpError
objets peuvent avoir un statusCode
propriété avec une valeur comme le 404
ou 403
ou 500
.
JavaScript permet d’utiliser des throw
avec n’importe quel argument, donc, techniquement, nos classes d’erreur personnalisées n’avez pas besoin d’hériter de Error
. Mais si nous héritons, alors il devient possible d’utiliser des obj instanceof Error
pour identifier les objets d’erreur. Il est donc préférable d’hériter d’elle.
Au fur et à mesure que l’application se développe, nos propres erreurs forment naturellement une hiérarchie., Par exemple, la balise HttpTimeoutError
peut hériter de HttpError
, et ainsi de suite.
erreur D’extension
à titre d’exemple, considérons une fonctionreadUser(json)
qui devrait lire JSON avec les données utilisateur.
Voici un exemple de comment un valide json
peut regarder:
let json = `{ "name": "John", "age": 30 }`;
en Interne, nous allons utiliser la balise JSON.parse
. S’il reçoit json
mal formé, il lance SyntaxError
., Mais même si json
est syntaxiquement correct, cela ne signifie pas que c’est un utilisateur valide, Non? Il peut manquer les données nécessaires. Par exemple, il peut ne pas avoir name
et age
propriétés qui sont essentiels pour nos utilisateurs.
notre fonctionreadUser(json)
non seulement Lira JSON, mais vérifiera (« validera”) les données. S’il n’y a pas de champs obligatoires, ou si le format est incorrect, alors c’est une erreur. Et ce n’est pas un SyntaxError
, car les données sont syntaxiquement correctes, mais un autre type d’erreur., Nous l’appellerons ValidationError
et créerons une classe pour cela. Une erreur de ce genre devrait également porter les informations sur le champ incriminé.
notre classeValidationError
devrait hériter de la classeError
intégrée.
cette classe est intégrée, mais voici son code approximatif afin que nous puissions comprendre ce que nous étendons:
héritons maintenant deValidationError
et essayons-le en action:
Veuillez noter: dans la ligne(1)
nous appelons le constructeur parent., JavaScript nous oblige à appeler super
dans le constructeur enfant, c’est donc obligatoire. Le constructeur parent définit la propriété message
.
Le constructeur parent définit également le name
propriété "Error"
, donc dans la ligne (2)
nous remettre à la bonne valeur.,
nous allons essayer de l’utiliser dans la balise readUser(json)
:
Le try..catch
bloc dans le code ci-dessus s’occupe à la fois de notre ValidationError
et intégré dans la balise SyntaxError
à partir de JSON.parse
.
veuillez regarder comment nous utilisonsinstanceof
pour vérifier le type d’erreur spécifique dans la ligne(*)
.,
On pourrait aussi regarder err.name
, comme ceci:
// ...// instead of (err instanceof SyntaxError)} else if (err.name == "SyntaxError") { // (*)// ...
Le instanceof
version est beaucoup mieux, parce que dans le futur nous allons étendre ValidationError
, faire des sous-types, comme PropertyRequiredError
. Et instanceof
la vérification continuera à fonctionner pour les nouvelles classes héritantes. Donc, c’est l’avenir.
Il est également important que sicatch
rencontre une erreur inconnue, il la replace dans la ligne(**)
., Le bloc catch
ne sait que Gérer les erreurs de validation et de syntaxe, d’autres types (dus à une faute de frappe dans le code ou à d’autres inconnues) devraient tomber.
héritage supplémentaire
La classeValidationError
est très générique. Beaucoup de choses peuvent mal se passer. La propriété peut être absente ou elle peut être dans un mauvais format (comme une valeur de chaîne pour age
). Faisons une classe plus concrète PropertyRequiredError
, exactement pour les propriétés absentes. Il contiendra des informations supplémentaires sur la propriété qui manque.,
La nouvelle classe PropertyRequiredError
est facile à utiliser: nous avons seulement besoin de passer le nom de la propriété: new PropertyRequiredError(property)
. Le message
lisible par l’homme est généré par le constructeur.
veuillez noter que this.name
dans PropertyRequiredError
le constructeur est à nouveau assigné manuellement. Cela peut devenir un peu fastidieux-attribuer this.name = <class name>
dans chaque classe d’erreur personnalisée. Nous pouvons l’éviter en créant notre propre classe « erreur de base »qui attribue this.name = this.constructor.name
. Et puis héritez de toutes nos erreurs personnalisées.,
appelons-le.
Voici le code avec et d’autres classes d’erreurs personnalisées, simplifiées:
maintenant, les erreurs personnalisées sont beaucoup plus courtes, en particulierValidationError
, car nous nous sommes débarrassés de la ligne"this.name = ..."
dans le constructeur.
Emballage exceptions
Le but de la fonction: readUser
dans le code ci-dessus est « pour lire les données de l’utilisateur”. Il peut se produire différents types d’erreurs dans le processus., Pour l’instant nous avons: SyntaxError
et ValidationError
, mais dans l’avenir readUser
fonction peut croître et probablement générer d’autres types d’erreurs.
Le code qui appelle readUser
doit gérer ces erreurs. En ce moment, il utilise plusieurs if
s dans le bloc catch
, qui vérifient la classe et gèrent les erreurs connues et relancent les inconnues.
Le schéma est comme ceci:
Dans le code ci-dessus, nous pouvons voir deux types d’erreurs, mais il peut être plus.,
Si la fonctionreadUser
génère plusieurs types d’erreurs, alors nous devrions nous demander: voulons-nous vraiment vérifier tous les types d’erreurs un par un à chaque fois?
Souvent, la réponse est « Non”: nous aimerions être « un niveau au-dessus de tout ça”. Nous voulons juste savoir s’il y avait une « erreur de lecture de données” – pourquoi exactement c’est arrivé est souvent hors de propos (le message d’erreur le décrit). Ou, mieux encore, nous aimerions avoir un moyen d’obtenir les détails de l’erreur, mais seulement si nous en avons besoin.
la technique que nous décrivons ici s’appelle « wrapping exceptions”.,
- Nous allons faire une nouvelle classe
ReadError
pour représenter un générique de « lecture des données” erreur. - La fonction
readUser
va les données de capture des erreurs de lecture qui se produisent à l’intérieur, commeValidationError
etSyntaxError
, et de générer unReadError
à la place. - Le
ReadError
objet de conserver la référence à l’origine de l’erreur dans soncause
propriété.,
Puis le code qui appelle readUser
vous n’avez qu’à vérifier ReadError
, pas pour tous les types de données des erreurs de lecture. Et s’il a besoin de plus de détails sur une erreur, il peut vérifier sa propriété cause
.,
Voici le code qui définit ReadError
et illustre son utilisation dans readUser
et try..catch
:
Dans le code ci-dessus, readUser
fonctionne exactement comme décrit, les prises accessoires, la syntaxe et les erreurs de validation et jette ReadError
erreurs au lieu (inconnu erreurs sont relancés comme d’habitude).
donc le code externe vérifieinstanceof ReadError
et c’est tout. Pas besoin de lister tous les types d’erreurs possibles.,
l’approche est appelée « encapsulation des exceptions”, car nous prenons des exceptions « de bas niveau” et les « encapsulons” dans ReadError
qui est plus abstrait. Il est largement utilisé dans la programmation orientée objet.
Résumé
- Nous pouvons hériter de
Error
et d’autres intégrés dans des classes d’erreur normalement. Nous avons juste besoin de prendre soin de la balisename
bien et n’oubliez pas d’appelersuper
. - On peut utiliser
instanceof
pour vérifier les erreurs. Cela fonctionne également avec l’héritage., Mais parfois, nous avons un objet d’erreur provenant d’une bibliothèque tierce et il n’y a pas de moyen facile d’obtenir sa classe. Ensuite, la propriéténame
peut être utilisée pour de telles vérifications. - L’encapsulation des exceptions est une technique répandue: une fonction gère les exceptions de bas niveau et crée des erreurs de plus haut niveau au lieu de diverses erreurs de bas niveau. Les exceptions de bas niveau deviennent parfois des propriétés de cet objet comme
err.cause
dans les exemples ci-dessus, mais ce n’est pas strictement requis.