Node.js ERROR 带你快速理解 Node.js 的错误处理机制

ERROR简介

Node.js 的错误分为四类:

  • 标准 JavaScript 错误,如 EvalErrorSynctaxErrorRangeErrorReferenceErrorTypeErrorURIError
  • 系统错误,如通过程序我们想打开一个文件,但是系统中不存在这个文件,就会抛出系统错误
  • 通过程序代码 throw() 抛出的错误
  • 断言错误,通过模块 assert 抛出的错误

同步API和异步API

Node.js的API主要有两种风格,同步和异步,如何区分呢,大部分异步API一般都有一个回调函数 callback 作为其参数,而大部分同步API则不会,例如:

// 异步 API
const fs = require('fs');
fs.readFile('/etc/passwd', (err, data) => {
  if (err) console.log(err);
  else console.log(data);
});

// 同步 API
fs.readFileSync('/etc/passwd');

Node.js 风格的回调

Node.js 大部分的异步方法都接受一个回调函数作为参数,我们通过该回调函数的第一个参数来判断是否发生了错误,如果是 null,则没有发生错误,如果不是 null,则调用该方法出现了错误,我们管这种回调叫做 Node.js 风格的回调

const fs = require('fs');

fs.readFile('/some/file/that/does-not-exist', function(err, data){
  if (err) {
    console.error('There was an error', err);
    return;
  }
  console.log(data);
});

注意:如果想在异步方法的回调函数里面抛出错误,不要放在 try / catch 代码块中,这样不仅不会捕获到异常,而且未捕获的异常可能会造成程序停止

// 这样不会捕获异常:
const fs = require('fs');

try {
  fs.readFile('/some/file/that/does-not-exist', (err, data) => {
    // mistaken assumption: throwing here...
    if (err) {
      throw err; // 抛出错误,但是无法被捕获到
    }
  });
} catch (err) {
  // 无法被捕获到
  console.error(err);
}

因回调函数还没有执行,try / catch 代码已经执行完毕并退出,所以无法捕获错误。如果想捕获错误,可以使用 process.on('uncaughtException') (或者 Domain 模块来处理,但 Domain 模块已被新版本弃用,这里只是提一嘴,不推荐使用)方法来处理,可以把上面的代码改造成:

const fs = require('fs');

fs.readFile('/some/file/that/does-not-exist', (err, data) => {
    // mistaken assumption: throwing here...
    if(err) {
        throw err; 
    }
});

process.on('uncaughtException', (err) => {
    console.log(err);
})

错误传播和拦截

Node.js 支持多种机制来处理应用程序运行时发生的错误。如何处理这些错误完全取决于错误的类型和被调用的 API 的风格,所有的 JavaScript 错误和大部分同步 API 都用 try / catch 机制处理:

const fs = require('fs');
try {
  const m = 1;
  const n = m + z; // javaScript 错误
  fs.readFileSync('./test.js');  // 同步API
} catch (err) {
  // 在这处理错误
}

异步 API 分为两种处理方式:一种是 Node.js 回调风格的 API,前面已有介绍另一种方式:如果一个对象是一个 EventEmitter 时,如 StreamEvent 等模块,调用这个对象的异步方法时可以通过这个对象的 error 事件处理:

const net = require('net');
const connection = net.connect('localhost'); // EventEmitter

// 绑定 error 事件
connection.on('error', (err) => {
  // 处理 err
  console.error(err);
});

connection.pipe(process.stdout);

注意:如果不用 error 事件处理,我们的程序将会崩溃,该错误也可以用 process.on('uncaughtException') 来捕获

CLASS Error

Node.js 的错误机制不会解释为什么会发生错误,它只会通过追踪栈信息来尽可能的描述该错误

new Error(message)

创建一个 Error 实例,message 是个字符串,也可以是一个对象(如果是对象,则 Node.js 先会把这个对象转化成字符串,再调用 new Error(message)

Error.captureStackTrace(targetObject[, constructorOpt])

targetObject 对象设置一个 stack 属性,记录 targetObject 的追踪栈信息,constructorOpt是一个函数,如果传了该参数,则该参数会在追踪栈信息中隐藏:

function MyError() {
  Error.captureStackTrace(this, MyError); // MyError会在结果中隐藏
}
new MyError().stack;
Error.stackTraceLimit

追踪栈信息的条数,默认值是 10,可以设置为其他值,如果设置的不是数字或者是负数,则不会追踪任何栈信息

Error Object
  • error.code 错误码,参照 Node.js Error Codes
  • error.message 错误信息
  • error.stack 追踪栈信息
try {
  Error.stackTraceLimit = 15;
  const m = z++;
} catch (e) {
  console.log(e.stack);
}
// ReferenceError: z is not defined
//   at Object. (C:\Users\papa_\.WebStorm2017.3\config\consoles\ide\ide-scripting.js:78:13)
//   at Module._compile (module.js:635:30)
//   at Object.Module._extensions..js (module.js:646:10)
//   at Module.load (module.js:554:32)
//   at tryModuleLoad (module.js:497:12)
//   at Function.Module._load (module.js:489:3)
//   at Function.Module.runMain (module.js:676:10)
//   at startup (bootstrap_node.js:187:16)
//   at bootstrap_node.js:608:3
  • C:\Users\papa_\.WebStorm2017.3\config\consoles\ide\ide-scripting.js:78:13 带有有绝对路径的一般表示用户程序的调用
  • module.js:635:30 没有绝对路径的一般表示 Node.js 的调用
  • native 一个方法描述一般表示 V8 引擎的调用

结语:本文介绍了 Node.js 的错误异常处理机制,跟原生JS还是有很大的差别,合理的处理 ERROR 会使我们的程序更健壮也会让开发人员更容易地确定问题并解决;原文档中有关系统错误做了详细的说明,因为跟 linux 的系统错误类似,在这就不做解释了;大部分异步同步 API 的处理方式都是与本文所述一致的的,但有一些特殊的 API 可能处理的方式不同,使用的时候请查阅文档

  • Node.js ERROR 官方文档。
  • Node.js 文档版本为: v8.9.1

作者 小菜荔枝原创 转载请联系作者获得授权

你可能感兴趣的:(Node.js ERROR 带你快速理解 Node.js 的错误处理机制)