Node.js中的Errors错误对象-错误对象及错误的传递与捕获

 2015年12月16日    261     声明


所有错误对象都继承自Errors类或是该类的一个实例,这些类或实例都至少会实现一些必要的属性。对于错误的处理,Node.js提供了两种处理方式:回调式错误传递错误事件


1. Node中的Errors错误对象

Errors错误对象会在Node.js程序发生异常时产生,Node.js中有两类错误对象:JavaScript 错误系统错误。所有错误对象都继承自JavaScript Errors类或是该类的一个实例,这些类或实例都至少会实现一些必要的属性。

当一个操作因为语言语法或是语言运行时层面的原因,一个JavaScript 错误就会产生并引发异常。如果一个操作是由于系统限制而不被允许的,就会产生系统错误。错误发生时,会有对应的客户端代码,这可以帮助我们判断错误位置,然后可以捕获错误或通过API传递错误。

Node错误处理对象中的API让我们可以根据需要定义合适的错误类型,并可以客户端代码来捕获传递错误。对于Exceptions异常信息,可以使用try/catch进行捕获。但对于回调中的错误,确只能通过回调传递处理。


2. 错误的传递与捕获机制

Node.js所有的异步或同步API,都会将无效参数视为异常,如果传递了非法参数,会立即生成并抛出一个Error异常。

对于同步API(如:fs.readFileSync)将会抛出一个错误。抛出值的处理方式,是将错误信息包装成一个Exceptions异常信息。该异常可以使用try { } catch(err) { }捕获。

而对于异步API,Node.js提供了两种错误处理机制:一种是Node.js回调式错误处理(一般在单个操作中使用)、另一种是错误事件(一般在多个操作中使用)。

2.1 Node.js回调式错误处理

Node.js定义了回调式错误传递,即:将回调函数的第一个参数做为错误对象,通过这种机制,使我们可以捕获Exceptions之外的回调函数中的异常。

Node.js回调式错误处理的回调函数中,至少有一个参数 -- error,如果没有发生错误时为null,有错误时是Error实例。

var fs = require('fs');

fs.readFile('/some/file/that/does-not-exist', function nodeStyleCallback(err, data) {
  console.log(err)  // Error: ENOENT
  console.log(data) // undefined | null
});

fs.readFile('/some/file/that/does-exist', function(err, data) {
  console.log(err)  // null
  console.log(data) // 
})

注意try { } catch(err) { }不能捕获异步API生成的错误。下面是刚接触Node的人常犯的一个错误:

// 这种方式捕获不到异步操作中的错误
var fs = require('fs');

try {
  fs.readFile('/some/file/that/does-not-exist', function(err, data) {
    // 异步错误是发生在这里的...
    if (err) {
      throw err;
    }
  });
} catch(err) {
  // 这里捕获不到异步错误
  console.log(err); // Error: ENOENT
}

上面的错误处理方式并不能正常运行,在Node的回调函数执行时,外围的代码try { } catch(err) { }已经退出了。

在大多数情况,在Node风格的回调函数内部抛出错误会使进程挂掉。如果启用了domain,它可以捕获被抛出的错误;类似,如果给process.on('uncaughtException')添加了监听器,也会捕获到错误。


2.2 错误事件

Node.js提供的另一种错误处理机制是error事件。这种处理方式常被用在基于或基于event emitter的API中,它们本身就代表了一系列的异步操作,而其中的每一个操作都可能成功或失败。如果在错误的源头没有添加error事件的监听器,那么error会被抛出。这时,进程会因为一个未处理的异常而挂掉,除非提供了合适的domain,或监听了process.on('uncaughtException')事件。

var net = require('net');

var connection = net.connect('localhost');

// 为stream添加一个"error"事件处理
connection.on('error', function(err) {
  // 如果遇到连接被系统重置、连接失败、或任命其它连接意外时
  //  error 都会在这儿捕获到
  console.error(err);
});

connection.pipe(process.stdout);

这种“未监听错误时会抛出错误”的行为不仅限于Node.js提供的API,用户创建的基于event emitters的API也存在这种情况。示例:

var events = require('events');

var ee = new events.EventEmitter;

setImmediate(function() {
  // 会导致进行崩溃,因为没有"error"事件监听
  ee.emit('error', new Error('崩溃吧'));
});