错误处理
众所周知Node 应用是依托在一个拥有大量共享状态的进程中,所以只要里面有错误而且还未及捕获,那么恭喜你,准备加班吧。
先举个栗子,看一下下面的代码:
var http = require('http');
var serv = http.createServer(function() {
throw new Error('错误未捕获');
});
serv.listen(3010);
错误未及时捕获,程序直接崩溃:
从错误输出,你可以看到调用堆栈从事件轮询一路到回调函数。Node 之所以会这样处理,主要是因为在发生未捕捉的错误时,进程就会变得不确定。之后可能就无法正常工作了,如果始终不处理的话,就会一直抛出意料之外的错误,这样就很难调试了。
可以通过添加uncaughtException 处理器,可以全部捕获未被捕获的 err,此时你可以针对不同错误进行不同操作了。
process.on('uncaughtException', function(err) {
console.log(err); //打印出错误
console.log(err.stack); //打印出错误的调用栈方便调试
process.exit(1); //手动退出进程
});
Node 中,许多像http、net 这样的原生模块都会分发error事件。如果该事件未处理,才会抛出未处理的异常。并且绝大多数的Node 异步Api 接受回调函数,第一个参数就是error 或者 null。
堆栈追踪
在JavaScript中,当发生错误时,控制台会打印出来一些错误信息,这些信息就被成为堆栈追踪。
先举个栗子看一下:
function a() {
b();
}
function b() {
c();
}
function c() {
throw new Error('手动错误');
}
a();
下面你可以清楚的看到导致错误发送执行函数的路径。
下面我们引入事件轮询看一下:
function c() {
setTimeout(function() {
throw new Error('手动错误');
}, 1000)
}
堆栈中一些有用的信息就丢失了。
所以,要捕获一个未来才执行到的函数错误是不可能的。这会直接抛出未捕获到的错误,例如如下的catch
代码是永远不会执行到的:
try{
setTimeout(function(){
throw new Error('手动错误');
},1000);
}catch(err){
console.log(err);
}
这就是为什么在Node.js中,每一步操作都需要正确的进行错误处理的原因了。