ERROR简介
Node.js 的错误分为四类:
- 标准 JavaScript 错误,如
EvalError
,SynctaxError
,RangeError
,ReferenceError
,TypeError
,URIError
- 系统错误,如通过程序我们想打开一个文件,但是系统中不存在这个文件,就会抛出系统错误
- 通过程序代码
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
时,如 Stream
,Event
等模块,调用这个对象的异步方法时可以通过这个对象的 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
作者 小菜荔枝原创 转载请联系作者获得授权