错误冒泡和拦截


【Error propagation and interception】

Node.js 支持多种机制来传播和处理应用运行时发生的错误。这些错误的报告和处理方式完全取决于 Error 的类型以及调用的 API 风格。

【Node.js supports several mechanisms for propagating and handling errors that occur while an application is running. How these errors are reported and handled depends entirely on the type of Error and the style of the API that is called.】

所有 JavaScript 错误都被作为异常处理,它们会_立即_生成并使用标准的 JavaScript throw 机制抛出错误。这些错误是通过 JavaScript 语言提供的 try…catch 结构 处理的。

【All JavaScript errors are handled as exceptions that immediately generate and throw an error using the standard JavaScript throw mechanism. These are handled using the try…catch construct provided by the JavaScript language.】

// Throws with a ReferenceError because z is not defined.
try {
  const m = 1;
  const n = m + z;
} catch (err) {
  // Handle the error here.
} 

JavaScript 的 throw 机制的任何使用都会引发一个异常,这个异常必须通过 try…catch 来处理,否则 Node.js 进程将立即退出。

【Any use of the JavaScript throw mechanism will raise an exception that must be handled using try…catch or the Node.js process will exit immediately.】

除了少数例外,同步 API(任何不接受 callback 函数的阻塞方法,例如 fs.readFileSync)将使用 throw 来报告错误。

【With few exceptions, Synchronous APIs (any blocking method that does not accept a callback function, such as fs.readFileSync), will use throw to report errors.】

异步 API 中发生的错误可能会以多种方式报告:

【Errors that occur within Asynchronous APIs may be reported in multiple ways:】

  • 大多数接受 callback 函数的异步方法都会将一个 Error 对象作为该函数的第一个参数传入。如果第一个参数不是 null 并且是 Error 的实例,那么就发生了一个应当处理的错误。

    const fs = require('node:fs');
    fs.readFile('a file that does not exist', (err, data) => {
      if (err) {
        console.error('There was an error reading the file!', err);
        return;
      }
      // Otherwise handle the data
    }); 
  • 当在一个是 EventEmitter 的对象上调用异步方法时,错误可以被传递到该对象的 'error' 事件。

    const net = require('node:net');
    const connection = net.connect('localhost');
    
    // Adding an 'error' event handler to a stream:
    connection.on('error', (err) => {
      // If the connection is reset by the server, or if it can't
      // connect at all, or on any sort of error encountered by
      // the connection, the error will be sent here.
      console.error(err);
    });
    
    connection.pipe(process.stdout); 
  • 在 Node.js API 中,有少数典型的异步方法仍可能使用 throw 机制来抛出必须通过 try…catch 处理的异常。没有这些方法的完整列表;请参阅每个方法的文档,以确定所需的正确错误处理机制。

对于 基于流的基于事件触发器的 API,使用 'error' 事件机制是最常见的,它们本身代表了一系列随时间进行的异步操作(与可能成功或失败的单一操作相对)。

【The use of the 'error' event mechanism is most common for stream-based and event emitter-based APIs, which themselves represent a series of asynchronous operations over time (as opposed to a single operation that may pass or fail).】

对于所有 EventEmitter 对象,如果没有提供 'error' 事件处理程序,错误将被抛出,导致 Node.js 进程报告未捕获的异常并崩溃,除非满足以下条件之一:适当使用了 domain 模块,或者已为 'uncaughtException' 事件注册了处理程序。

【For all EventEmitter objects, if an 'error' event handler is not provided, the error will be thrown, causing the Node.js process to report an uncaught exception and crash unless either: The domain module is used appropriately or a handler has been registered for the 'uncaughtException' event.】

const EventEmitter = require('node:events');
const ee = new EventEmitter();

setImmediate(() => {
  // This will crash the process because no 'error' event
  // handler has been added.
  ee.emit('error', new Error('This will crash'));
}); 

以这种方式生成的错误无法使用 try…catch 拦截,因为它们是在调用代码已经退出之后抛出的。

【Errors generated in this way cannot be intercepted using try…catch as they are thrown after the calling code has already exited.】

开发者必须查阅每种方法的文档,以确定这些方法引发的错误是如何传播的。

【Developers must refer to the documentation for each method to determine exactly how errors raised by those methods are propagated.】