Un guide définitif pour gérer les erreurs en JavaScript
Publié: 2022-01-24La loi de Murphy stipule que tout ce qui peut mal tourner finira par mal tourner. Cela s'applique un peu trop bien dans le monde de la programmation. Si vous créez une application, il y a de fortes chances que vous créiez des bogues et d'autres problèmes. Les erreurs en JavaScript sont l'un de ces problèmes courants !
Le succès d'un produit logiciel dépend de la capacité de ses créateurs à résoudre ces problèmes avant de nuire à leurs utilisateurs. Et JavaScript, parmi tous les langages de programmation, est connu pour sa conception moyenne de gestion des erreurs.
Si vous construisez une application JavaScript, il y a de fortes chances que vous vous trompiez avec les types de données à un moment ou à un autre. Sinon, vous pourriez finir par remplacer un indéfini par un opérateur nul ou triple égal ( ===
) par un double opérateur égal ( ==
).
C'est humain de faire des erreurs. C'est pourquoi nous allons vous montrer tout ce que vous devez savoir sur la gestion des erreurs en JavaScript.
Cet article vous guidera à travers les erreurs de base en JavaScript et vous expliquera les différentes erreurs que vous pourriez rencontrer. Vous apprendrez ensuite comment identifier et corriger ces erreurs. Il existe également quelques conseils pour gérer efficacement les erreurs dans les environnements de production.
Sans plus tarder, commençons !
Que sont les erreurs JavaScript ?
Les erreurs de programmation font référence à des situations qui ne permettent pas à un programme de fonctionner normalement. Cela peut se produire lorsqu'un programme ne sait pas comment gérer le travail en cours, par exemple lorsqu'il essaie d'ouvrir un fichier inexistant ou d'atteindre un point de terminaison d'API basé sur le Web alors qu'il n'y a pas de connectivité réseau.
Ces situations poussent le programme à lancer des erreurs à l'utilisateur, indiquant qu'il ne sait pas comment procéder. Le programme collecte autant d'informations que possible sur l'erreur, puis signale qu'il ne peut pas continuer.
Les programmeurs intelligents essaient de prédire et de couvrir ces scénarios afin que l'utilisateur n'ait pas à trouver un message d'erreur technique comme "404" indépendamment. Au lieu de cela, ils affichent un message beaucoup plus compréhensible : "La page est introuvable".
Les erreurs en JavaScript sont des objets affichés chaque fois qu'une erreur de programmation se produit. Ces objets contiennent de nombreuses informations sur le type de l'erreur, l'instruction à l'origine de l'erreur et la trace de la pile lorsque l'erreur s'est produite. JavaScript permet également aux programmeurs de créer des erreurs personnalisées pour fournir des informations supplémentaires lors du débogage des problèmes.
Propriétés d'une erreur
Maintenant que la définition d'une erreur JavaScript est claire, il est temps de plonger dans les détails.
Les erreurs dans JavaScript comportent certaines propriétés standard et personnalisées qui aident à comprendre la cause et les effets de l'erreur. Par défaut, les erreurs en JavaScript contiennent trois propriétés :
- message : Une valeur de chaîne qui porte le message d'erreur
- name : Le type d'erreur qui s'est produite (nous approfondirons cela dans la section suivante)
- stack : la trace de la pile du code exécuté lorsque l'erreur s'est produite.
De plus, les erreurs peuvent également contenir des propriétés telles que columnNumber, lineNumber, fileName, etc., pour mieux décrire l'erreur. Cependant, ces propriétés ne sont pas standard et peuvent ou non être présentes dans chaque objet d'erreur généré à partir de votre application JavaScript.
Comprendre le suivi de la pile
Une trace de pile est la liste des appels de méthode dans lesquels se trouvait un programme lorsqu'un événement tel qu'une exception ou un avertissement se produit. Voici à quoi ressemble un exemple de trace de pile accompagnée d'une exception :

Comme vous pouvez le voir, il commence par afficher le nom et le message d'erreur, suivis d'une liste des méthodes appelées. Chaque appel de méthode indique l'emplacement de son code source et la ligne à laquelle il a été invoqué. Vous pouvez utiliser ces données pour naviguer dans votre base de code et identifier quel morceau de code est à l'origine de l'erreur.
Cette liste de méthodes est organisée de manière empilée. Il montre où votre exception a été levée pour la première fois et comment elle s'est propagée à travers les appels de méthode empilés. L'implémentation d'un catch pour l'exception ne la laissera pas se propager dans la pile et bloquer votre programme. Cependant, vous voudrez peut-être laisser les erreurs fatales non détectées pour bloquer intentionnellement le programme dans certains scénarios.
Erreurs vs exceptions
La plupart des gens considèrent généralement les erreurs et les exceptions comme la même chose. Cependant, il est essentiel de noter une différence légère mais fondamentale entre eux.
Pour mieux comprendre cela, prenons un exemple rapide. Voici comment définir une erreur en JavaScript :
const wrongTypeError = TypeError("Wrong type found, expected character")
Et c'est ainsi que l'objet wrongTypeError
devient une exception :
throw wrongTypeError
Cependant, la plupart des gens ont tendance à utiliser la forme abrégée qui définit les objets d'erreur tout en les lançant :
throw TypeError("Wrong type found, expected character")
C'est une pratique courante. Cependant, c'est l'une des raisons pour lesquelles les développeurs ont tendance à confondre les exceptions et les erreurs. Par conséquent, connaître les bases est essentiel même si vous utilisez des raccourcis pour faire votre travail rapidement.
Types d'erreurs en JavaScript
Il existe une gamme de types d'erreurs prédéfinis dans JavaScript. Ils sont automatiquement choisis et définis par le runtime JavaScript chaque fois que le programmeur ne gère pas explicitement les erreurs dans l'application.
Cette section vous guidera à travers certains des types d'erreurs les plus courants en JavaScript et vous expliquera quand et pourquoi elles se produisent.
RangeError
Une RangeError est levée lorsqu'une variable est définie avec une valeur en dehors de sa plage de valeurs légales. Cela se produit généralement lors du passage d'une valeur en tant qu'argument à une fonction, et la valeur donnée ne se situe pas dans la plage des paramètres de la fonction. Cela peut parfois devenir difficile à résoudre lors de l'utilisation de bibliothèques tierces mal documentées, car vous devez connaître la plage de valeurs possibles pour que les arguments transmettent la valeur correcte.
Certains des scénarios courants dans lesquels RangeError se produit sont :
- Essayer de créer un tableau de longueurs illégales via le constructeur Array.
- Passer de mauvaises valeurs à des méthodes numériques comme
toExponential()
,toPrecision()
,toFixed()
, etc. - Passer des valeurs illégales à des fonctions de chaîne comme
normalize()
.
Erreur de référence
Une ReferenceError se produit lorsque quelque chose ne va pas avec la référence d'une variable dans votre code. Vous avez peut-être oublié de définir une valeur pour la variable avant de l'utiliser, ou vous essayez peut-être d'utiliser une variable inaccessible dans votre code. Dans tous les cas, parcourir la trace de la pile fournit de nombreuses informations pour trouver et corriger la référence de variable en cause.
Certaines des raisons courantes pour lesquelles les erreurs de référence se produisent sont :
- Faire une faute de frappe dans un nom de variable.
- Essayer d'accéder à des variables de portée de bloc en dehors de leurs portées.
- Référencer une variable globale à partir d'une bibliothèque externe (comme $ de jQuery) avant qu'elle ne soit chargée.
Erreur de syntaxe
Ces erreurs sont parmi les plus simples à corriger puisqu'elles indiquent une erreur dans la syntaxe du code. Étant donné que JavaScript est un langage de script qui est interprété plutôt que compilé, ceux-ci sont lancés lorsque l'application exécute le script contenant l'erreur. Dans le cas des langages compilés, ces erreurs sont identifiées lors de la compilation. Ainsi, les fichiers binaires de l'application ne sont pas créés tant qu'ils ne sont pas corrigés.
Certaines des raisons courantes pour lesquelles des erreurs de syntaxe peuvent se produire sont :
- Virgules inversées manquantes
- Parenthèses fermantes manquantes
- Mauvais alignement des accolades ou d'autres caractères
C'est une bonne pratique d'utiliser un outil de linting dans votre IDE pour identifier ces erreurs pour vous avant qu'elles n'atteignent le navigateur.
Erreur-type
TypeError est l'une des erreurs les plus courantes dans les applications JavaScript. Cette erreur est créée lorsqu'une valeur ne s'avère pas être d'un type attendu particulier. Certains des cas courants où cela se produit sont:
- Invoquer des objets qui ne sont pas des méthodes.
- Tentative d'accès aux propriétés d'objets nuls ou indéfinis
- Traiter une chaîne comme un nombre ou vice versa
Il y a beaucoup plus de possibilités où une TypeError peut se produire. Nous examinerons quelques instances célèbres plus tard et apprendrons comment les corriger.
Erreur interne
Le type InternalError est utilisé lorsqu'une exception se produit dans le moteur d'exécution JavaScript. Cela peut ou non indiquer un problème avec votre code.
Le plus souvent, InternalError ne se produit que dans deux scénarios :
- Lorsqu'un correctif ou une mise à jour de l'environnement d'exécution JavaScript comporte un bogue qui lève des exceptions (cela se produit très rarement)
- Lorsque votre code contient des entités trop volumineuses pour le moteur JavaScript (par exemple, trop de cas de commutation, des initialiseurs de tableau trop volumineux, trop de récursivité)
L'approche la plus appropriée pour résoudre cette erreur consiste à identifier la cause via le message d'erreur et à restructurer la logique de votre application, si possible, pour éliminer le pic soudain de charge de travail sur le moteur JavaScript.
URIError
URIError se produit lorsqu'une fonction globale de gestion d'URI telle que decodeURIComponent
est utilisée illégalement. Cela indique généralement que le paramètre passé à l'appel de méthode n'était pas conforme aux normes URI et n'a donc pas été analysé correctement par la méthode.
Le diagnostic de ces erreurs est généralement facile puisqu'il suffit d'examiner les arguments en faveur de la malformation.
EvalErreur
Une EvalError se produit lorsqu'une erreur se produit avec un appel de fonction eval()
. La fonction eval()
est utilisée pour exécuter du code JavaScript stocké dans des chaînes. Cependant, étant donné que l'utilisation de la fonction eval()
est fortement déconseillée en raison de problèmes de sécurité et que les spécifications ECMAScript actuelles ne lancent plus la classe EvalError
, ce type d'erreur existe simplement pour maintenir la compatibilité descendante avec le code JavaScript hérité.
Si vous travaillez sur une ancienne version de JavaScript, vous pouvez rencontrer cette erreur. Dans tous les cas, il est préférable d'enquêter sur le code exécuté dans l'appel de fonction eval()
pour toute exception.
Création de types d'erreur personnalisés
Bien que JavaScript offre une liste adéquate de classes de types d'erreurs à couvrir pour la plupart des scénarios, vous pouvez toujours créer un nouveau type d'erreur si la liste ne répond pas à vos besoins. Le fondement de cette flexibilité réside dans le fait que JavaScript vous permet de lancer n'importe quoi littéralement avec la commande throw
.
Donc, techniquement, ces déclarations sont entièrement légales :
throw 8 throw "An error occurred"
Cependant, lancer un type de données primitif ne fournit pas de détails sur l'erreur, tels que son type, son nom ou la trace de pile qui l'accompagne. Pour résoudre ce problème et normaliser le processus de gestion des erreurs, la classe Error
a été fournie. Il est également déconseillé d'utiliser des types de données primitifs lors de la levée d'exceptions.
Vous pouvez étendre la classe Error
pour créer votre classe d'erreur personnalisée. Voici un exemple de base de la façon dont vous pouvez le faire :
class ValidationError extends Error { constructor(message) { super(message); this.name = "ValidationError"; } }
Et vous pouvez l'utiliser de la manière suivante :
throw ValidationError("Property not found: name")
Et vous pouvez ensuite l'identifier à l'aide du mot-clé instanceof
:
try { validateForm() // code that throws a ValidationError } catch (e) { if (e instanceof ValidationError) // do something else // do something else }
Top 10 des erreurs les plus courantes en JavaScript
Maintenant que vous comprenez les types d'erreurs courants et comment créer vos erreurs personnalisées, il est temps d'examiner certaines des erreurs les plus courantes auxquelles vous serez confronté lors de l'écriture de code JavaScript.
1. Erreur de plage non détectée
Cette erreur se produit dans Google Chrome dans différents scénarios. Tout d'abord, cela peut arriver si vous appelez une fonction récursive et qu'elle ne se termine pas. Vous pouvez vérifier cela vous-même dans la Chrome Developer Console :

Donc, pour résoudre une telle erreur, assurez-vous de définir correctement les cas limites de votre fonction récursive. Une autre raison pour laquelle cette erreur se produit est si vous avez passé une valeur qui est hors de la plage du paramètre d'une fonction. Voici un exemple :

Le message d'erreur indiquera généralement ce qui ne va pas avec votre code. Une fois les modifications apportées, le problème sera résolu.

2. TypeError non intercepté : impossible de définir la propriété
Cette erreur se produit lorsque vous définissez une propriété sur une référence indéfinie. Vous pouvez reproduire le problème avec ce code :
var list list.count = 0
Voici la sortie que vous recevrez :

Pour corriger cette erreur, initialisez la référence avec une valeur avant d'accéder à ses propriétés. Voici à quoi cela ressemble une fois réparé :

3. TypeError non intercepté : impossible de lire la propriété
C'est l'une des erreurs les plus fréquentes en JavaScript. Cette erreur se produit lorsque vous tentez de lire une propriété ou d'appeler une fonction sur un objet indéfini. Vous pouvez le reproduire très facilement en exécutant le code suivant dans une console Chrome Developer :
var func func.call()
Voici la sortie :

Un objet indéfini est l'une des nombreuses causes possibles de cette erreur. Une autre cause importante de ce problème peut être une initialisation incorrecte de l'état lors du rendu de l'interface utilisateur. Voici un exemple concret d'une application React :
import React, { useState, useEffect } from "react"; const CardsList = () => { const [state, setState] = useState(); useEffect(() => { setTimeout(() => setState({ items: ["Card 1", "Card 2"] }), 2000); }, []); return ( <> {state.items.map((item) => ( <li key={item}>{item}</li> ))} </> ); }; export default CardsList;
L'application démarre avec un conteneur d'état vide et reçoit certains éléments après un délai de 2 secondes. Le délai est mis en place pour imiter un appel réseau. Même si votre réseau est super rapide, vous serez toujours confronté à un léger retard en raison duquel le composant sera rendu au moins une fois. Si vous essayez d'exécuter cette application, vous recevrez l'erreur suivante :

En effet, au moment du rendu, le conteneur d'état n'est pas défini ; ainsi, il n'existe aucun items
de propriété dessus. La correction de cette erreur est facile. Il vous suffit de fournir une valeur par défaut initiale au conteneur d'état.
// ... const [state, setState] = useState({items: []}); // ...
Maintenant, après le délai défini, votre application affichera une sortie similaire :

Le correctif exact dans votre code peut être différent, mais l'essentiel ici est de toujours initialiser correctement vos variables avant de les utiliser.
4. TypeError : 'undefined' n'est pas un objet
Cette erreur se produit dans Safari lorsque vous essayez d'accéder aux propriétés ou d'appeler une méthode sur un objet non défini. Vous pouvez exécuter le même code ci-dessus pour reproduire l'erreur vous-même.

La solution à cette erreur est également la même - assurez-vous que vous avez correctement initialisé vos variables et qu'elles ne sont pas indéfinies lors de l'accès à une propriété ou à une méthode.
5. TypeError : null n'est pas un objet
Ceci est, encore une fois, similaire à l'erreur précédente. Cela se produit sur Safari, et la seule différence entre les deux erreurs est que celle-ci est levée lorsque l'objet dont la propriété ou la méthode est en cours d'accès est null
au lieu de undefined
. Vous pouvez reproduire cela en exécutant le morceau de code suivant :
var func = null func.call()
Voici la sortie que vous recevrez :

Étant donné que null
est une valeur explicitement définie sur une variable et non attribuée automatiquement par JavaScript. Cette erreur ne peut se produire que si vous essayez d'accéder à une variable que vous avez définie sur null
par vous-même. Donc, vous devez revoir votre code et vérifier si la logique que vous avez écrite est correcte ou non.
6. TypeError : impossible de lire la propriété "longueur"
Cette erreur se produit dans Chrome lorsque vous essayez de lire la longueur d'un objet null
ou undefined
. La cause de ce problème est similaire aux problèmes précédents, mais il se produit assez fréquemment lors de la gestion des listes ; il mérite donc une mention spéciale. Voici comment vous pouvez reproduire le problème :

Cependant, dans les nouvelles versions de Chrome, cette erreur est signalée comme Uncaught TypeError: Cannot read properties of undefined
. Voici à quoi cela ressemble maintenant :

Le correctif, encore une fois, consiste à s'assurer que l'objet dont vous essayez d'accéder à la longueur existe et n'est pas défini sur null
.
7. TypeError : 'undefined' n'est pas une fonction
Cette erreur se produit lorsque vous essayez d'invoquer une méthode qui n'existe pas dans votre script, ou elle existe mais ne peut pas être référencée dans le contexte d'appel. Cette erreur se produit généralement dans Google Chrome et vous pouvez la résoudre en vérifiant la ligne de code qui génère l'erreur. Si vous trouvez une faute de frappe, corrigez-la et vérifiez si cela résout votre problème.
Si vous avez utilisé le mot-clé d'auto-référence this
dans votre code, this
erreur peut survenir s'il n'est pas correctement lié à votre contexte. Considérez le code suivant :
function showAlert() { alert("message here") } document.addEventListener("click", () => { this.showAlert(); })
Si vous exécutez le code ci-dessus, il lancera l'erreur dont nous avons discuté. Cela se produit parce que la fonction anonyme transmise en tant qu'écouteur d'événement est exécutée dans le contexte du document
.
En revanche, la fonction showAlert
est définie dans le contexte de la window
.
Pour résoudre ce problème, vous devez passer la référence appropriée à la fonction en la liant avec la méthode bind()
:
document.addEventListener("click", this.showAlert.bind(this))
8. ReferenceError : l'événement n'est pas défini
Cette erreur se produit lorsque vous essayez d'accéder à une référence non définie dans la portée appelante. Cela se produit généralement lors de la gestion des événements, car ils vous fournissent souvent une référence appelée event
dans la fonction de rappel. Cette erreur peut se produire si vous oubliez de définir l'argument d'événement dans les paramètres de votre fonction ou si vous l'épelez mal.
Cette erreur peut ne pas se produire dans Internet Explorer ou Google Chrome (car IE propose une variable d'événement globale et Chrome attache automatiquement la variable d'événement au gestionnaire), mais elle peut se produire dans Firefox. Il est donc conseillé de garder un œil sur ces petites erreurs.
9. TypeError : Affectation à une variable constante
C'est une erreur qui découle d'une négligence. Si vous essayez d'assigner une nouvelle valeur à une variable constante, vous obtiendrez un tel résultat :

Bien que cela semble facile à corriger pour le moment, imaginez des centaines de déclarations de variables de ce type et l'une d'entre elles définie par erreur comme const
au lieu de let
! Contrairement à d'autres langages de script comme PHP, il y a une différence minime entre le style de déclaration des constantes et des variables en JavaScript. Il est donc conseillé de vérifier vos déclarations avant tout lorsque vous rencontrez cette erreur. Vous pouvez également rencontrer cette erreur si vous oubliez que ladite référence est une constante et que vous l'utilisez comme variable. Cela indique soit une négligence, soit une faille dans la logique de votre application. Assurez-vous de vérifier cela lorsque vous essayez de résoudre ce problème.
10. (inconnu) : erreur de script
Une erreur de script se produit lorsqu'un script tiers envoie une erreur à votre navigateur. Cette erreur est suivie de (inconnu) car le script tiers appartient à un domaine différent de celui de votre application. Le navigateur masque d'autres détails pour empêcher la fuite d'informations sensibles du script tiers.
Vous ne pouvez pas résoudre cette erreur sans connaître tous les détails. Voici ce que vous pouvez faire pour obtenir plus d'informations sur l'erreur :
- Ajoutez l'attribut
crossorigin
dans la balise de script. - Définissez l'en-tête
Access-Control-Allow-Origin
correct sur le serveur hébergeant le script. - [Facultatif] Si vous n'avez pas accès au serveur hébergeant le script, vous pouvez envisager d'utiliser un proxy pour relayer votre demande au serveur et la renvoyer au client avec les en-têtes corrects.
Une fois que vous pouvez accéder aux détails de l'erreur, vous pouvez alors régler le problème, qui sera probablement lié à la bibliothèque tierce ou au réseau.
Comment identifier et prévenir les erreurs en JavaScript
Bien que les erreurs décrites ci-dessus soient les plus courantes et les plus fréquentes en JavaScript, vous rencontrerez, s'appuyer sur quelques exemples ne suffira jamais. Il est essentiel de comprendre comment détecter et prévenir tout type d'erreur dans une application JavaScript lors de son développement. Voici comment vous pouvez gérer les erreurs en JavaScript.
Lancer et attraper manuellement les erreurs
Le moyen le plus fondamental de gérer les erreurs générées manuellement ou par le moteur d'exécution consiste à les intercepter. Comme la plupart des autres langages, JavaScript propose un ensemble de mots-clés pour gérer les erreurs. Il est essentiel de connaître chacun d'eux en profondeur avant de vous lancer dans la gestion des erreurs dans votre application JavaScript.
jeter
Le premier et le plus fondamental des mots-clés de l'ensemble est throw
. Il est évident que le mot clé throw est utilisé pour générer des erreurs afin de créer manuellement des exceptions dans l'environnement d'exécution JavaScript. Nous en avons déjà discuté plus tôt dans l'article, et voici l'essentiel de la signification de ce mot-clé :
- Vous pouvez
throw
n'importe quoi, y compris des nombres, des chaînes et des objetsError
. - Cependant, il n'est pas conseillé de lancer des types de données primitifs tels que des chaînes et des nombres car ils ne contiennent pas d'informations de débogage sur les erreurs.
- Exemple :
throw TypeError("Please provide a string")
essayer
Le mot-clé try
est utilisé pour indiquer qu'un bloc de code peut lever une exception. Sa syntaxe est :
try { // error-prone code here }
Il est important de noter qu'un bloc catch
doit toujours suivre le bloc try
pour gérer efficacement les erreurs.
capture
Le mot-clé catch
est utilisé pour créer un bloc catch. Ce bloc de code est responsable de la gestion des erreurs détectées par le bloc try
final. Voici sa syntaxe :
catch (exception) { // code to handle the exception here }
Et voici comment vous implémentez les blocs try
et catch
ensemble :
try { // business logic code } catch (exception) { // error handling code }
Contrairement à C++ ou Java, vous ne pouvez pas ajouter plusieurs blocs catch
à un bloc try
en JavaScript. Cela signifie que vous ne pouvez pas faire ceci :
try { // business logic code } catch (exception) { if (exception instanceof TypeError) { // do something } } catch (exception) { if (exception instanceof RangeError) { // do something } }
Au lieu de cela, vous pouvez utiliser une instruction if...else
ou une instruction switch case à l'intérieur du bloc catch unique pour gérer tous les cas d'erreur possibles. Cela ressemblerait à ceci :
try { // business logic code } catch (exception) { if (exception instanceof TypeError) { // do something } else if (exception instanceof RangeError) { // do something else } }
finalement
Le mot clé finally
est utilisé pour définir un bloc de code qui est exécuté après qu'une erreur a été traitée. Ce bloc est exécuté après les blocs try et catch.
De plus, le bloc finally sera exécuté quel que soit le résultat des deux autres blocs. Cela signifie que même si le bloc catch ne peut pas gérer entièrement l'erreur ou si une erreur est renvoyée dans le bloc catch, l'interpréteur exécutera le code dans le bloc finally avant que le programme ne plante.
Pour être considéré comme valide, le bloc try en JavaScript doit être suivi soit d'un bloc catch, soit d'un bloc finally. Sans aucun de ceux-ci, l'interpréteur lèvera une SyntaxError. Par conséquent, assurez-vous de suivre vos blocs try avec au moins l'un d'eux lors de la gestion des erreurs.
Gérer les erreurs globalement avec la méthode onerror()
La méthode onerror()
est disponible pour tous les éléments HTML pour gérer les erreurs qui peuvent survenir avec eux. Par exemple, si une balise img
ne trouve pas l'image dont l'URL est spécifiée, elle déclenche sa méthode onerror pour permettre à l'utilisateur de gérer l'erreur.
En règle générale, vous fournissez une autre URL d'image dans l'appel onerror pour que la balise img
se replie. Voici comment vous pouvez le faire via JavaScript :
const image = document.querySelector("img") image.onerror = (event) => { console.log("Error occurred: " + event) }
Cependant, vous pouvez utiliser cette fonctionnalité pour créer un mécanisme global de gestion des erreurs pour votre application. Voici comment procéder :
window.onerror = (event) => { console.log("Error occurred: " + event) }
Avec ce gestionnaire d'événements, vous pouvez vous débarrasser des multiples blocs try...catch
qui traînent dans votre code et centraliser la gestion des erreurs de votre application de la même manière que la gestion des événements. Vous pouvez attacher plusieurs gestionnaires d'erreurs à la fenêtre pour maintenir le principe de responsabilité unique des principes de conception SOLID. L'interpréteur parcourra tous les gestionnaires jusqu'à ce qu'il atteigne celui qui convient.
Passer les erreurs via des rappels
Alors que les fonctions simples et linéaires permettent de gérer les erreurs de manière simple, les rappels peuvent compliquer l'affaire.
Considérez le morceau de code suivant :
Besoin d'une solution d'hébergement qui vous donne un avantage concurrentiel ? Kinsta vous couvre avec une vitesse incroyable, une sécurité de pointe et une mise à l'échelle automatique. Découvrez nos forfaits
const calculateCube = (number, callback) => { setTimeout(() => { const cube = number * number * number callback(cube) }, 1000) } const callback = result => console.log(result) calculateCube(4, callback)
La fonction ci-dessus illustre une condition asynchrone dans laquelle une fonction prend un certain temps pour traiter les opérations et renvoie le résultat ultérieurement à l'aide d'un rappel.
Si vous essayez d'entrer une chaîne au lieu de 4 dans l'appel de fonction, vous obtiendrez NaN
en conséquence.
Cela doit être géré correctement. Voici comment:
const calculateCube = (number, callback) => { setTimeout(() => { if (typeof number !== "number") throw new Error("Numeric argument is expected") const cube = number * number * number callback(cube) }, 1000) } const callback = result => console.log(result) try { calculateCube(4, callback) } catch (e) { console.log(e) }
Cela devrait résoudre le problème idéalement. Cependant, si vous essayez de passer une chaîne à l'appel de fonction, vous recevrez ceci :

Même si vous avez implémenté un bloc try-catch lors de l'appel de la fonction, il indique toujours que l'erreur n'est pas interceptée. L'erreur est renvoyée après l'exécution du bloc catch en raison du délai d'attente.
Cela peut se produire rapidement dans les appels réseau, où des retards inattendus se glissent. Vous devez couvrir de tels cas lors du développement de votre application.
Voici comment gérer correctement les erreurs dans les rappels :
const calculateCube = (number, callback) => { setTimeout(() => { if (typeof number !== "number") { callback(new TypeError("Numeric argument is expected")) return } const cube = number * number * number callback(null, cube) }, 2000) } const callback = (error, result) => { if (error !== null) { console.log(error) return } console.log(result) } try { calculateCube('hey', callback) } catch (e) { console.log(e) }
Maintenant, la sortie sur la console sera :

Cela indique que l'erreur a été correctement gérée.
Gérer les erreurs dans les promesses
La plupart des gens ont tendance à préférer les promesses pour gérer les activités asynchrones. Les promesses ont un autre avantage : une promesse rejetée ne met pas fin à votre script. Cependant, vous devez toujours implémenter un bloc catch pour gérer les erreurs dans les promesses. Pour mieux comprendre cela, réécrivons la fonction calculateCube()
en utilisant Promises :
const delay = ms => new Promise(res => setTimeout(res, ms)); const calculateCube = async (number) => { if (typeof number !== "number") throw Error("Numeric argument is expected") await delay(5000) const cube = number * number * number return cube } try { calculateCube(4).then(r => console.log(r)) } catch (e) { console.log(e) }
Le délai d'attente du code précédent a été isolé dans la fonction de delay
pour la compréhension. Si vous essayez d'entrer une chaîne au lieu de 4, le résultat obtenu ressemblera à ceci :

Encore une fois, cela est dû au fait que la Promise
génère l'erreur après que tout le reste a été exécuté. La solution à ce problème est simple. Ajoutez simplement un appel catch()
à la chaîne de promesse comme ceci :
calculateCube("hey") .then(r => console.log(r)) .catch(e => console.log(e))
Maintenant, la sortie sera :

Vous pouvez observer à quel point il est facile de gérer les erreurs avec des promesses. De plus, vous pouvez chaîner un bloc finally()
et l'appel de promesse pour ajouter du code qui s'exécutera une fois la gestion des erreurs terminée.
Alternativement, vous pouvez également gérer les erreurs dans les promesses en utilisant la technique traditionnelle try-catch-finally. Voici à quoi ressemblerait votre appel de promesse dans ce cas :
try { let result = await calculateCube("hey") console.log(result) } catch (e) { console.log(e) } finally { console.log('Finally executed") }
Cependant, cela ne fonctionne qu'à l'intérieur d'une fonction asynchrone. Par conséquent, la meilleure façon de gérer les erreurs dans les promesses est de chaîner catch
et finally
à l'appel de promesse.
lancer/attraper vs onerror() vs rappels vs promesses : quel est le meilleur ?
Avec quatre méthodes à votre disposition, vous devez savoir choisir la plus appropriée dans un cas d'utilisation donné. Voici comment vous pouvez décider par vous-même :
lancer/attraper
Vous utiliserez cette méthode la plupart du temps. Assurez-vous d'implémenter des conditions pour toutes les erreurs possibles dans votre bloc catch et n'oubliez pas d'inclure un bloc finally si vous devez exécuter des routines de nettoyage de la mémoire après le bloc try.
Cependant, trop de blocs try/catch peuvent rendre votre code difficile à maintenir. Si vous vous trouvez dans une telle situation, vous souhaiterez peut-être gérer les erreurs via le gestionnaire global ou la méthode promise.
Lorsque vous décidez entre les blocs try/catch asynchrones et le catch()
de la promesse, il est conseillé d'utiliser les blocs try/catch asynchrones car ils rendront votre code linéaire et facile à déboguer.
une erreur()
Il est préférable d'utiliser la méthode onerror()
lorsque vous savez que votre application doit gérer de nombreuses erreurs et qu'elles peuvent être bien dispersées dans la base de code. La méthode onerror
vous permet de gérer les erreurs comme s'il s'agissait simplement d'un autre événement géré par votre application. Vous pouvez définir plusieurs gestionnaires d'erreurs et les attacher à la fenêtre de votre application lors du rendu initial.
Cependant, vous devez également vous rappeler que la méthode onerror()
peut être inutilement difficile à configurer dans des projets plus petits avec une portée d'erreur moindre. Si vous êtes sûr que votre application ne générera pas trop d'erreurs, la méthode traditionnelle lancer/attraper fonctionnera le mieux pour vous.
Rappels et promesses
La gestion des erreurs dans les rappels et les promesses diffère en raison de la conception et de la structure de leur code. Cependant, si vous choisissez entre ces deux avant d'avoir écrit votre code, il serait préférable de faire des promesses.
En effet, les promesses ont une construction intégrée pour enchaîner un bloc catch()
et un bloc finally()
pour gérer facilement les erreurs. Cette méthode est plus simple et plus propre que de définir des arguments supplémentaires/de réutiliser des arguments existants pour gérer les erreurs.
Keep Track of Changes With Git Repositories
Many errors often arise due to manual mistakes in the codebase. While developing or debugging your code, you might end up making unnecessary changes that may cause new errors to appear in your codebase. Automated testing is a great way to keep your code in check after every change. However, it can only tell you if something's wrong. If you don't take frequent backups of your code, you'll end up wasting time trying to fix a function or a script that was working just fine before.
This is where git plays its role. With a proper commit strategy, you can use your git history as a backup system to view your code as it evolved through the development. You can easily browse through your older commits and find out the version of the function working fine before but throwing errors after an unrelated change.
You can then restore the old code or compare the two versions to determine what went wrong. Modern web development tools like GitHub Desktop or GitKraken help you to visualize these changes side by side and figure out the mistakes quickly.
A habit that can help you make fewer errors is running code reviews whenever you make a significant change to your code. If you're working in a team, you can create a pull request and have a team member review it thoroughly. This will help you use a second pair of eyes to spot out any errors that might have slipped by you.
Best Practices for Handling Errors in JavaScript
The above-mentioned methods are adequate to help you design a robust error handling approach for your next JavaScript application. However, it would be best to keep a few things in mind while implementing them to get the best out of your error-proofing. Here are some tips to help you.
1. Use Custom Errors When Handling Operational Exceptions
We introduced custom errors early in this guide to give you an idea of how to customize the error handling to your application's unique case. It's advisable to use custom errors wherever possible instead of the generic Error
class as it provides more contextual information to the calling environment about the error.
On top of that, custom errors allow you to moderate how an error is displayed to the calling environment. This means that you can choose to hide specific details or display additional information about the error as and when you wish.
You can go so far as to format the error contents according to your needs. This gives you better control over how the error is interpreted and handled.
2. Do Not Swallow Any Exceptions
Even the most senior developers often make a rookie mistake — consuming exceptions levels deep down in their code.
You might come across situations where you have a piece of code that is optional to run. If it works, great; if it doesn't, you don't need to do anything about it.
In these cases, it's often tempting to put this code in a try block and attach an empty catch block to it. However, by doing this, you'll leave that piece of code open to causing any kind of error and getting away with it. This can become dangerous if you have a large codebase and many instances of such poor error management constructs.
The best way to handle exceptions is to determine a level on which all of them will be dealt and raise them until there. This level can be a controller (in an MVC architecture app) or a middleware (in a traditional server-oriented app).
This way, you'll get to know where you can find all the errors occurring in your app and choose how to resolve them, even if it means not doing anything about them.
3. Use a Centralized Strategy for Logs and Error Alerts
Logging an error is often an integral part of handling it. Those who fail to develop a centralized strategy for logging errors may miss out on valuable information about their app's usage.
An app's event logs can help you figure out crucial data about errors and help to debug them quickly. If you have proper alerting mechanisms set up in your app, you can know when an error occurs in your app before it reaches a large section of your user base.
It's advisable to use a pre-built logger or create one to suit your needs. You can configure this logger to handle errors based on their levels (warning, debug, info, etc.), and some loggers even go so far as to send logs to remote logging servers immediately. This way, you can watch how your application's logic performs with active users.
4. Notify Users About Errors Appropriately
Another good point to keep in mind while defining your error handling strategy is to keep the user in mind.
All errors that interfere with the normal functioning of your app must present a visible alert to the user to notify them that something went wrong so the user can try to work out a solution. If you know a quick fix for the error, such as retrying an operation or logging out and logging back in, make sure to mention it in the alert to help fix the user experience in real-time.
In the case of errors that don't cause any interference with the everyday user experience, you can consider suppressing the alert and logging the error to a remote server for resolving later.
5. Implement a Middleware (Node.js)
The Node.js environment supports middlewares to add functionalities to server applications. You can use this feature to create an error-handling middleware for your server.
The most significant benefit of using middleware is that all of your errors are handled centrally in one place. You can choose to enable/disable this setup for testing purposes easily.
Here's how you can create a basic middleware:
const logError = err => { console.log("ERROR: " + String(err)) } const errorLoggerMiddleware = (err, req, res, next) => { logError(err) next(err) } const returnErrorMiddleware = (err, req, res, next) => { res.status(err.statusCode || 500) .send(err.message) } module.exports = { logError, errorLoggerMiddleware, returnErrorMiddleware }
Vous pouvez ensuite utiliser ce middleware dans votre application comme ceci :
const { errorLoggerMiddleware, returnErrorMiddleware } = require('./errorMiddleware') app.use(errorLoggerMiddleware) app.use(returnErrorMiddleware)
Vous pouvez désormais définir une logique personnalisée dans le middleware pour gérer les erreurs de manière appropriée. Vous n'avez plus à vous soucier de l'implémentation de constructions individuelles de gestion des erreurs dans votre base de code.
6. Redémarrez votre application pour gérer les erreurs du programmeur (Node.js)
Lorsque les applications Node.js rencontrent des erreurs de programmation, elles ne génèrent pas nécessairement une exception et essaient de fermer l'application. Ces erreurs peuvent inclure des problèmes résultant d'erreurs du programmeur, comme une consommation élevée du processeur, un gonflement de la mémoire ou des fuites de mémoire. La meilleure façon de les gérer est de redémarrer l'application en douceur en la faisant planter via le mode cluster Node.js ou un outil unique comme PM2. Cela peut garantir que l'application ne se bloque pas lors de l'action de l'utilisateur, ce qui présente une expérience utilisateur terrible.
7. Attraper toutes les exceptions non interceptées (Node.js)
Vous ne pouvez jamais être sûr d'avoir couvert toutes les erreurs possibles pouvant survenir dans votre application. Par conséquent, il est essentiel de mettre en œuvre une stratégie de secours pour intercepter toutes les exceptions non interceptées de votre application.
Voici comment procéder :
process.on('uncaughtException', error => { console.log("ERROR: " + String(error)) // other handling mechanisms })
Vous pouvez également identifier si l'erreur qui s'est produite est une exception standard ou une erreur opérationnelle personnalisée. En fonction du résultat, vous pouvez quitter le processus et le redémarrer pour éviter un comportement inattendu.
8. Attraper tous les rejets de promesses non gérées (Node.js)
De la même manière que vous ne pouvez jamais couvrir toutes les exceptions possibles, il y a de fortes chances que vous manquiez de gérer tous les rejets de promesses possibles. Cependant, contrairement aux exceptions, les rejets de promesses ne génèrent pas d'erreurs.
Ainsi, une promesse importante qui a été rejetée peut s'échapper comme un avertissement et laisser votre application ouverte à la possibilité de se heurter à un comportement inattendu. Par conséquent, il est crucial de mettre en œuvre un mécanisme de secours pour gérer le rejet des promesses.
Voici comment procéder :
const promiseRejectionCallback = error => { console.log("PROMISE REJECTED: " + String(error)) } process.on('unhandledRejection', callback)
tweeter Résumé
Comme tout autre langage de programmation, les erreurs sont assez fréquentes et naturelles en JavaScript. Dans certains cas, vous devrez peut-être même lancer des erreurs intentionnellement pour indiquer la bonne réponse à vos utilisateurs. Par conséquent, comprendre leur anatomie et leurs types est très crucial.
De plus, vous devez être équipé des bons outils et techniques pour identifier et empêcher les erreurs de supprimer votre application.
Dans la plupart des cas, une stratégie solide pour gérer les erreurs avec une exécution soignée suffit pour tous les types d'applications JavaScript.
Y a-t-il d'autres erreurs JavaScript que vous n'avez toujours pas pu résoudre ? Des techniques pour gérer les erreurs JS de manière constructive? Faites-nous savoir dans les commentaires ci-dessous!