Fortgeschrittene Fehlerbehandlung in JavaScript: von try/catch bis zu globalen Abfangmechanismen
\n\nFehlerbehandlung ist nicht einfach nur „Code in try/catch einwickeln". In echten Node.js-Produktionsanwendungen ermöglicht ein durchdachtes Ausnahmemanagement, Serverabstürze zu vermeiden, Probleme korrekt zu protokollieren und dem Benutzer verständliche Meldungen zu geben. In diesem Artikel behandeln wir fortgeschrittene Techniken der Fehlerbehandlung in JavaScript, die über die grundlegende Syntax hinausgehen.
\n\n1. Tieferes Eintauchen in try/catch und finally
\n\nDas klassische Konstrukt try...catch...finally bleibt die Grundlage der synchronen Verarbeitung. Auf fortgeschrittener Ebene ist es jedoch wichtig, die Nuancen seiner Funktionsweise zu verstehen.
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\nWichtige Punkte:
\n- \n
- Der
finally-Block wird immer ausgeführt, selbst wenn intryodercatcheinreturnsteht. \n - Verwenden Sie die eingebauten Fehlerklassen (
TypeError,RangeError,SyntaxError) für eine präzise Identifikation. \n - Fangen Sie keine Fehler ab, die Sie nicht behandeln können – lassen Sie sie nach oben steigen. \n
2. Benutzerdefinierte Fehlerklassen und Erweiterung von Error
\n\nFür große Projekte reichen die standardmäßigen Fehlertypen nicht aus. Die Erstellung eigener Klassen ermöglicht das Hinzufügen von Metadaten (HTTP-Status, Fehlercode, Kontext) und vereinfacht die Filterung.
\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// Verwendung\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\nWarum das wichtig ist: Benutzerdefinierte Fehler ermöglichen die zentrale Verarbeitung verschiedener Szenarien (z. B. in Express.js-Middleware) und die Rückgabe eines strukturierten JSON an den Client.
\n\n3. Fehlerbehandlung in asynchronem Code: async/await und Promise
\n\nIn Node.js ist der Großteil des Codes asynchron. Fehler in Promise und async/await erfordern eine besondere Herangehensweise.
3.1. Promise-Behandlung
\n\nfunction fetchUserData(userId) {\n return new Promise((resolve, reject) => {\n if (userId <= 0) {\n reject(new RangeError('Invalid user ID'));\n }\n // Simulation einer Datenbankabfrage\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. async/await-Behandlung
\n\nasync function getUserProfile(userId) {\n try {\n const user = await fetchUserData(userId);\n const posts = await fetchUserPosts(user.id