Gestion des erreurs en JavaScript : try/catch et au-delà
La gestion des erreurs est l'une des tâches clés du développement en JavaScript, en particulier dans l'environnement Node.js, où la stabilité d'une application serveur impacte directement l'expérience utilisateur. Les exceptions non gérées peuvent entraîner l'arrêt complet du processus et une perte de données. Dans cet article, nous aborderons non seulement le bloc classique try/catch, mais aussi des techniques avancées : l'utilisation de finally, la création de types d'erreurs personnalisés, la gestion des erreurs asynchrones et les meilleures pratiques pour Node.js.
1. Les bases : try, catch et finally
Le bloc try/catch est le mécanisme fondamental pour intercepter les exceptions synchrones. Si une erreur se produit dans le bloc try, l'exécution est immédiatement transférée au bloc catch. Le bloc finally s'exécute toujours — qu'il y ait eu une erreur ou non. C'est pratique pour libérer des ressources (fermeture de fichiers, de connexions).
const fs = require('fs');
function readConfig(path) { try { const data = fs.readFileSync(path, 'utf8'); console.log('Configuration chargée'); return JSON.parse(data); } catch (err) { console.error('Erreur lors de la lecture de la configuration :', err.message); return null; } finally { console.log('Tentative de lecture terminée'); }}
const config = readConfig('./config.json');console.log(config); // null en cas d'erreurImportant : catch n'intercepte que les erreurs survenues dans try. Les erreurs dans catch ou finally restent non gérées.
2. Types d'erreurs en JavaScript et Node.js
En JavaScript, il existe plusieurs types d'erreurs intégrés, chacun héritant de Error :
- SyntaxError — erreur syntaxique lors de l'analyse du code.
- ReferenceError — référence à une variable inexistante.
- TypeError — type de données invalide (par exemple, appel d'une non-fonction).
- RangeError — valeur en dehors de la plage autorisée.
- URIError — erreur lors du travail avec les URI (encodeURI/decodeURI).
Dans Node.js, s'ajoutent AssertionError (du module assert) et les erreurs système (EACCES, ENOENT, etc.) du module fs, qui contiennent le code d'erreur dans la propriété code.
try { require('fs').readFileSync('/nonexistent');} catch (err) { if (err.code === 'ENOENT') { console.log('Fichier non trouvé'); } else { console.log('Autre erreur :', err.message); }}3. Création d'erreurs personnalisées
Pour un contrôle plus précis de la logique de gestion, il est recommandé de créer vos propres classes d'erreurs, étendant Error. Cela permet de distinguer les erreurs de logique métier des défaillances système.
class ValidationError extends Error { constructor(message, field) { super(message); this.name = 'ValidationError'; this.field = field; }}
class DatabaseError extends Error { constructor(message, query) { super(message); this.name = 'DatabaseError'; this.query = query; }}
function saveUser(user) { if (!user.email) { throw new ValidationError('Email obligatoire', 'email'); } // simulation d'une erreur de base de données throw new DatabaseError('Délai de connexion dépassé', 'INSERT INTO users');}
try { saveUser({ name: 'Ivan' });} catch (err) { if (err instanceof ValidationError) { console.log(`Champ ${err.field} : ${err.message}`); } else if (err instanceof DatabaseError) { console.error(`Erreur BD (${err.query}) : ${err.message}`); // nouvelle tentative ou journalisation } else { console.error('Erreur inconnue :', err); }}L'utilisation de instanceof permet de construire des chaînes de gestionnaires sans avoir recours à la vérification de codes chaînes de caractères.