Gestion des erreurs en JavaScript : try/catch et bien plus : niveau avancé
La gestion des erreurs n'est pas simplement une protection contre les plantages d'application, mais un aspect fondamental de la construction de systèmes fiables et résilients en JavaScript et Node.js. L'utilisation de base de try/catch est familière à chaque développeur, mais dans les projets réels, surtout côté serveur, de nombreuses nuances apparaissent : flux asynchrones, chaînes de promesses, pannes globales et besoin d'erreurs personnalisées structurées. Dans cet article, nous allons analyser les techniques avancées de gestion des erreurs qui vous aideront à écrire un code plus propre et plus prévisible dans Node.js.
1. Plongée approfondie dans try/catch et l'asynchronisme
Le try/catch classique est synchrone. Il attrape parfaitement les erreurs à l'intérieur des fonctions normales, mais échoue face aux callbacks asynchrones ou aux promesses sans await. Dans Node.js, où 90% du code est asynchrone, cela devient souvent une cause d'exceptions "avalées".
Erreur : try/catch n'attrape pas l'erreur dans setTimeout
function dangerousAsync() { setTimeout(() => { throw new Error('Panne dans le minuteur !'); }, 1000);}
try { dangerousAsync();} catch (e) { console.log('Attrapé :', e.message); // Ce code NE s'exécutera PAS}Dans cet exemple, l'erreur est levée en dehors du contexte du try, et le processus Node.js se termine anormalement. La bonne approche consiste à utiliser des promesses ou async/await.
Solution : encapsuler le code asynchrone dans une Promise
function safeAsync() { return new Promise((resolve, reject) => { setTimeout(() => { reject(new Error('Panne dans le minuteur !')); }, 1000); });}
(async () => { try { await safeAsync(); } catch (e) { console.log('Attrapé :', e.message); // S'exécutera après 1 seconde }})();La règle principale : encapsulez toute opération asynchrone dans une promesse, et utilisez await à l'intérieur de try/catch. Cela garantit que l'erreur sera interceptée dans le contexte approprié.
2. Classes d'erreurs personnalisées : sémantique et contexte
Au lieu de lever new Error('Quelque chose s'est mal passé'), créez une hiérarchie de vos propres classes d'erreurs. Cela permet au niveau du gestionnaire de comprendre le type de panne et de réagir en conséquence (par exemple, journaliser, envoyer à un système de surveillance ou retourner un statut HTTP spécifique à l'utilisateur).
class AppError extends Error { constructor(message, statusCode = 500) { super(message); this.name = this.constructor.name; this.statusCode = statusCode; Error.captureStackTrace(this, this.constructor); }}
class ValidationError extends AppError { constructor(message) { super(message, 400); }}
class DatabaseError extends AppError { constructor(message, originalError) { super(message, 503); this.originalError = originalError; // Conserve l'erreur d'origine pour le débogage }}
// Utilisationfunction findUser(id) { if (!id) throw new ValidationError('L\\'ID utilisateur est obligatoire'); // ... logique qui peut lever une DatabaseError}Avantages de cette approche :
- Lisibilité : le nom de la classe indique immédiatement la nature du problème.
- Routage : dans le gestionnaire global, vous pouvez vérifier
instanceofet choisir la stratégie de réponse. - Champs supplémentaires : vous pouvez ajouter toutes les données nécessaires (
statusCode,originalError,userId, etc.).
3. Gestionnaires globaux d'erreurs dans Node.js
Même avec le contrôle le plus minutieux, des erreurs non traitées peuvent s'échapper. Dans Node.js, il existe deux événements clés pour les intercepter : uncaughtException et unhandledRejection
Blogs
Book Recommendations
Lire aussi