引言:为什么错误处理是可靠代码的基石
代码中的错误是不可避免的。它们可能由用户输入错误、网络故障、服务器上文件缺失或开发者的简单拼写错误引起。在 Node.js 环境中,代码异步执行并经常与外部资源(数据库、文件系统、API)交互,未处理的错误可能导致整个进程崩溃。良好的 JavaScript 错误处理能将脆弱的应用程序转变为稳定的服务。本文将解析所有关键机制:从经典的 try/catch 到创建自定义错误类以及处理异步代码。
1. 基础:try、catch、finally 和 throw
JavaScript 中处理异常的基本块是 try...catch...finally 结构。它允许“捕获”在“危险”代码段中发生的错误,并做出适当响应,而不会中断整个程序的执行。
try/catch 的语法和工作原理
可能抛出异常的代码放在 try 块中。如果发生错误,控制权会立即转移到 catch 块,其中可以访问错误对象。如果没有错误,则忽略 catch 块。
try { const data = JSON.parse('{"name": "安娜"}'); // 正确的 JSON console.log(data.name); // 输出:安娜} catch (error) { console.error('解析错误:', error.message);}// 继续执行现在模拟一个错误:
try { const data = JSON.parse('无效的 json'); // 错误! console.log(data.name);} catch (error) { console.error('解析错误:', error.message); // 输出:解析错误:Unexpected token 'н', ... is not valid JSON}console.log('程序仍在运行!'); // 此代码将执行finally 块:始终执行的代码
finally 块无论是否发生错误都会执行。它非常适合释放资源(关闭文件、数据库连接)或清理定时器。
let resource = null;try { resource = acquireResource(); // 获取资源 resource.doSomething(); // 危险操作} catch (error) { console.error('错误:', error);} finally { if (resource) { resource.close(); // 始终关闭资源 console.log('资源已释放。'); }}throw 操作符:创建自己的错误
您可以使用 throw 自行“抛出”错误。这对于验证输入数据或在违反业务逻辑时中断执行非常有用。可以传递任何内容作为参数,但最佳实践是使用 Error 对象或其子类。
function divide(a, b) { if (typeof a !== 'number' || typeof b !== 'number') { throw new Error('参数必须是数字'); } if (b === 0) { throw new Error('禁止除以零'); } return a / b;}
try { console.log(divide(10, 0));} catch (error) { console.error('错误:', error.message); // 错误:禁止除以零}2. 高级技巧:自定义错误类和类型化
在大型项目中,仅使用标准 Error 是不够的。需要区分网络错误、验证错误、授权错误等。为此,可以创建扩展内置 Error 的用户自定义类。
创建自定义错误
class ValidationError extends Error { constructor(message) { super(message); this.name = 'ValidationError'; // 用于检查的唯一名称 }}
class NetworkError extends Error { constructor(message, statusCode) { super(message); this.name = 'NetworkError'; this.statusCode = statusCode; }}
function fetchUser(id) { if (!id) { throw new Valida