在 Node.js 中运行的应用程序通常会遇到四类错误:
- 标准的 JavaScript 错误,例如
、 、 、 、 和 。 - 由底层操作系统约束触发的系统错误,例如尝试打开不存在的文件或尝试通过关闭的套接字发送数据。
- 由应用程序代码触发的用户指定的错误。
- AssertionError 是特殊的错误类,当 Node.js 检测到不应该发生的异常逻辑违规时会触发。 这些通常由 assert 模块引发。
Node.js 引发的所有 JavaScript 和系统错误都继承自标准的 JavaScript
错误的传播和拦截
Node.js 支持多种机制来传播和处理应用程序运行时发生的错误。 如何报告和处理这些错误完全取决于 Error 的类型和调用的 API 的风格。
所有的 JavaScript 错误都作为异常处理,使用标准的 JavaScript throw 机制立即生成并抛出错误。 这些是使用 JavaScript 语言提供的 try…catch构造处理的。
任何使用 JavaScript throw 机制都会引发异常,必须使用 try…catch 处理,否则 Node.js 进程将立即退出。
除了少数例外,同步的 API(任何不接受 callback 函数的阻塞方法,例如 fs.readFileSync)都使用 throw 来报告错误。
异步的 API 中发生的错误可以以多种方式报告:
- 大多数接受 callback 函数的异步方法将接受作为第一个参数传给该函数的 Error 对象。 如果第一个参数不是 null 并且是 Error 的实例,则发生了应该处理的错误。
- 当在 EventEmitter 对象上调用异步方法时,错误可以路由到该对象的 ‘error’ 事件。
- Node.js API 中的一些典型的异步方法可能仍然使用 throw 机制来引发必须使用 try…catch 处理的异常。 没有此类方法的完整列表;请参阅每种方法的文档以确定所需的适当错误处理机制。
错误优先的回调
Node.js 核心 API 暴露的大多数异步方法都遵循称为错误优先回调的惯用模式。 使用这种模式,回调函数作为参数传给方法。 当操作完成或出现错误时,回调函数将使用 Error 对象(如果有)作为第一个参数传入。 如果没有出现错误,则第一个参数将作为 null 传入。
const fs = require('fs');
function errorFirstCallback(err, data) {
if (err) {
console.error('There was an error', err);
return;
}
console.log(data);
}
fs.readFile('/some/file/that/does-not-exist', errorFirstCallback);
fs.readFile('/some/file/that/does-exist', errorFirstCallback);
JavaScript try…catch
机制不能用于拦截异步 API 产生的错误。 初学者的一个常见错误是尝试在错误优先的回调中使用 throw:
const fs = require('fs');
// 这行不通:
try {
fs.readFile('/some/file/that/does-not-exist', (err, data) => {
// 错误的假设:在这里抛出...
if (err) {
throw err;
}
});
} catch (err) {
// 这不会捕获抛出的错误!
console.error(err);
}
这不起作用,因为传给 fs.readFile() 的回调函数是异步调用的。 当回调被调用时,周围的代码(包括 try…catch 块)已经退出。 大多数情况下,在回调中抛出错误会使 Node.js 进程崩溃。 如果启用了域,或者已经在 process.on(‘uncaughtException’) 注册了句柄,则可以拦截此类错误。