Gestion avancée des erreurs en JavaScript : de try/catch aux intercepteurs globaux
\n\nLa gestion des erreurs ne se limite pas à « envelopper le code dans un try/catch ». Dans les applications de production réelles sous Node.js, une gestion judicieuse des exceptions permet d'éviter les plantages du serveur, de journaliser correctement les problèmes et de fournir des messages compréhensibles à l'utilisateur. Dans cet article, nous allons explorer les techniques avancées de gestion des erreurs en JavaScript qui vont au-delà de la syntaxe de base.
\n\n1. Plongée approfondie dans try/catch et finally
\n\nLa construction classique try...catch...finally reste la base de la gestion synchrone. Cependant, à un niveau avancé, il est important de comprendre les nuances de son fonctionnement.
function riskyOperation(value) {\n if (typeof value !== 'number') {\n throw new TypeError('Argument must be a number');\n }\n if (value < 0) {\n throw new RangeError('Value cannot be negative');\n }\n return Math.sqrt(value);\n}\n\ntry {\n const result = riskyOperation(-4);\n console.log('Result:', result);\n} catch (error) {\n if (error instanceof TypeError) {\n console.error('Type Error:', error.message);\n } else if (error instanceof RangeError) {\n console.error('Range Error:', error.message);\n } else {\n console.error('Unknown error:', error);\n }\n} finally {\n console.log('Cleanup: always executed');\n}\n\nPoints clés :
\n- \n
- Le bloc
finallys'exécute toujours, même sitryoucatchcontient unreturn. \n - Utilisez les classes d'erreurs intégrées (
TypeError,RangeError,SyntaxError) pour une identification précise. \n - N'interceptez pas les erreurs que vous ne pouvez pas gérer — laissez-les remonter. \n
2. Classes d'erreurs personnalisées et extension de Error
\n\nPour les grands projets, les types d'erreurs standard ne suffisent pas. La création de vos propres classes permet d'ajouter des métadonnées (statut HTTP, code d'erreur, contexte) et simplifie le filtrage.
\n\nclass AppError extends Error {\n constructor(message, statusCode, code) {\n super(message);\n this.name = 'AppError';\n this.statusCode = statusCode;\n this.code = code;\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\nclass ValidationError extends AppError {\n constructor(message, field) {\n super(message, 400, 'VALIDATION_ERROR');\n this.field = field;\n }\n}\n\nclass DatabaseError extends AppError {\n constructor(message, query) {\n super(message, 500, 'DB_ERROR');\n this.query = query;\n }\n}\n\n// Utilisation\ntry {\n throw new ValidationError('Email is required', 'email');\n} catch (error) {\n if (error instanceof ValidationError) {\n console.log(`Field: ${error.field}, Status: ${error.statusCode}`);\n }\n}\n\nPourquoi c'est important : les erreurs personnalisées permettent de gérer centralement différents scénarios (par exemple, dans un middleware Express.js) et de renvoyer un JSON structuré au client.
\n\n3. Gestion des erreurs dans le code asynchrone : async/await et Promise
\n\nDans Node.js, la majeure partie du code est asynchrone. Les erreurs dans les Promise et async/await nécessitent une approche particulière.
3.1. Gestion des Promise
\n\nfunction fetchUserData(userId) {\n return new Promise((resolve, reject) => {\n if (userId <= 0) {\n reject(new RangeError('Invalid user ID'));\n }\n // simulation d'une requête à la base de données\n setTimeout(() => resolve({ id: userId, name: 'Alice' }), 100);\n });\n}\n\nfetchUserData(-1)\n .then(user => console.log(user))\n .catch(error => {\n console.error('Promise rejected:', error.message);\n })\n .finally(() => console.log('Cleanup after promise'));\n\n3.2. Gestion avec async/await
\n\nasync function getUserProfile(userId) {\n try {\n const user = await fetchUserData(userId);\n const posts = await fetchUserPosts(user.id