JavaScript 中的高级错误处理:从 try/catch 到全局拦截器
\n\n错误处理不仅仅是“用 try/catch 包裹代码”。在真实的 Node.js 生产应用中,妥善的异常管理可以避免服务器崩溃、正确记录问题并向用户提供清晰的信息。在本文中,我们将探讨 JavaScript 中超越基本语法的高级错误处理技术。
\n\n1. 深入理解 try/catch 和 finally
\n\n经典的 try...catch...finally 结构仍然是同步处理的基础。然而,在高级层面,理解其工作细节至关重要。
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\n关键点:
\n- \n
finally块始终执行,即使try或catch中有return。 \n - 使用内置错误类(
TypeError、RangeError、SyntaxError)进行精确识别。 \n - 不要捕获你无法处理的错误——让它们向上冒泡。 \n
2. 自定义错误类和扩展 Error
\n\n对于大型项目,标准错误类型是不够的。创建自己的类可以添加元数据(HTTP 状态码、错误代码、上下文)并简化过滤。
\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// 使用\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\n为什么这很重要:自定义错误允许集中处理不同场景(例如,在 Express.js 中间件中)并向客户端返回结构化的 JSON。
\n\n3. 异步代码中的错误处理:async/await 和 Promise
\n\n在 Node.js 中,大部分代码是异步的。Promise 和 async/await 中的错误需要特殊处理。
3.1. Promise 处理
\n\nfunction fetchUserData(userId) {\n return new Promise((resolve, reject) => {\n if (userId <= 0) {\n reject(new RangeError('Invalid user ID'));\n }\n // 模拟数据库请求\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 处理
\n\nasync function getUserProfile(userId) {\n try {\n const user = await fetchUserData(userId);\n const posts = await fetchUserPosts(user.id