引言:为什么错误处理是可靠代码的基础
任何运行在 Node.js 上的应用程序迟早都会遇到异常情况:无效的用户输入、网络故障、磁盘文件缺失或来自数据库的错误数据。如果没有适当的错误处理,这些情况会导致服务器崩溃、内存泄漏或未定义行为。在 JavaScript 中,尤其是在 Node.js 环境下,try/catch 机制是构建容错系统的基本工具。在本文中,我们不仅会介绍经典的 try/catch,还会涵盖高级技术:自定义错误类、处理 Promise 和异步函数,以及日志记录的最佳实践。
基础:try、catch 和 finally 块
JavaScript 中错误处理的基本语法如下:
try { // 可能抛出异常的代码 const data = JSON.parse('{"name": "Node.js"}'); console.log(data.name);} catch (error) { // 错误处理 console.error('发生错误:', error.message);} finally { // 无论何种情况都会执行的代码 console.log('Finally 块已执行');}工作原理:
try— 包含可能存在风险的代码。catch— 捕获异常(如果发生)。error参数接收错误对象。finally— 始终执行,无论是否发生错误。非常适合用于关闭文件、释放资源或完成事务。
需要记住的重要一点:即使 try 或 catch 块中包含了 return 语句,finally 块仍然会执行。
JavaScript 中的错误类型
内置的错误构造函数有助于更精确地对异常进行分类:
Error— 所有错误的基类。SyntaxError— 语法错误(例如无效的 JSON)。TypeError— 数据类型不正确(例如调用非函数)。ReferenceError— 引用不存在的变量。RangeError— 超出允许的限制范围(例如递归)。
处理不同类型错误的示例:
try { const obj = null; console.log(obj.property); // TypeError} catch (err) { if (err instanceof TypeError) { console.log('类型错误:', err.message); } else if (err instanceof ReferenceError) { console.log('变量未找到'); } else { console.log('未知错误:', err); }}生成自定义错误:throw 运算符
有时需要显式地指示程序中发生了异常情况。这时会用到 throw 运算符。它可以抛出任何内容:字符串、数字、对象,但最好是抛出 Error 类或其子类的实例。
function divide(a, b) { if (b === 0) { throw new Error('不允许除以零'); } if (typeof a !== 'number' || typeof b !== 'number') { throw new TypeError('参数必须是数字'); } return a / b;}
try { const result = divide(10, 0); console.log(result);} catch (err) { console.error(err.name + ': ' + err.message);}为什么抛出 Error 对象比抛出字符串更好? Error 对象包含调用堆栈(stack),这对于在 Node.js 中进行调试至关重要。字符串无法提供此类信息。
创建自定义错误类
在实际项目(例如 Express Web 服务器)中,为不同情况(如 ValidationError、NotFoundError、DatabaseError)设置自定义错误类型非常方便。这简化了集中式错误处理。
class ValidationError extends Error {