王龑 — APRIL 08, 2015
很多 NodeJS 的开发者在抱怨异常处理太麻烦,我们会通过一些列博客梳理一下NodeJS中常见的异常处理的手段。
和大多数编程语言一样,在 NodeJS 里可以通过`throw`抛出一个异常:
```
throw new Error('Catch me');
```
为了捕获这个异常需要把代码包在`Try Catch`中:
```
try{
throw new Error('Catch me');
}catch(e){
// error captured
}
```
然而,由于 NodeJS 的异步特性,上述代码只需稍加改造就会失效:
```
try{
process.nextTick(function my_app(){
throw new Error('Catch me');
})
}catch(e){
// never called
}
```
在现实世界里,异常总是会产生在某个模块中。所谓模块就是能完成一个功能的单元,即使是一个简单的函数也可以被看做一个模块。随着项目代码行数增多,异步嵌套的复杂性加强,经常会有异常没捕获的情况发生。一个没有很强健壮性的 NodeJS 应用,会因为一个未捕获的异常就整个挂掉,导致服务不可用。要改变大家觉得NodeJS是脆弱的这个认识,需要开发者加深对这门语言异常处理机制的了解。
##uncaughtException
`uncaughtException` 其实是 NodeJS 进程的一个事件。如果进程里产生了一个异常而没有被任何`Try Catch`捕获会触发这个事件。为了简化问题,我们还是先看看同步情况下的例子。
```
function external() {
throw new Error('Catch me');
}
function internal() {
external();
}
internal(); //error will be thrown
```
在命令行里执行这个程序,脚本会在抛出异常的那一行中断。接下来,由于没有`Try Catch`,异常会一直冒泡直到事件循环为止,而NodeJS对异常的默认处理非常简单,处理的代码 *类似* 于:
```
function _MyFatalException(err){
if(!process.emit('uncaughtException',err)){
console.error(err.stack);
process.emit('exit',1);
}
}
```
NodeJS对于未捕获异常的默认处理是: - 触发 `uncaughtException` 事件 - 如果 uncaughtException 没有被监听,那么 - 打印异常的堆栈信息 - 触发进程的 exit 事件
如果你正在用 NodeJS 开发服务器,那么你肯定不希望偶然的一个异常让整个服务器挂掉。那么是不是只要监听了 `uncaughtException` 就可以阻止服务器的进程退出呢? 答案是可以,**但是不要这么做!**。看这个例子:
```
var express = require('express');
function external(cb) {
process.nextTick(function () {
throw new Error();
cb.call(null, 'sunny');
})
}
var app = express();
app.get('/weather', function (req, res) {
external(function (data) {
res.end('Weather of Beijing is ' + data);
})
})
app.listen(8018);
function noop(){}
process.on('uncaughtException', noop)
```
上面这个例子假设用户访问站点的时候可以看到当地的天气,我们用 `apache2-utils` 来模拟请求
> ab -n 1000 -c 20 http://localhost:8018/weather
糟糕!请求一直在等待,内存上涨。原因在于`res.end` 永远不会执行,现有的`I/O`处于等待的状态,已经开辟的资源不仅不会被释放,而且服务器还在不知疲倦地接受新的用户请求。
在 NodeJS 中处理异常是代价高昂的,而且一不小心就会导致内存泄露和让应用程序处于不稳定的状态。为了提高健壮性,我们可以用`Cluster`模式,由之而来的推荐做法是: - 针对发生异常的请求返回一个错误代码 - 出错的Worker不再接受新的请求 - 退出关闭Worker进程
***
**本文作者系[OneAPM](http://www.oneapm.com/)工程师王龑 ,想阅读更多好的[技术文章](http://code.oneapm.com/),请访问OneAPM官方技术博客。**
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30238867/viewspace-1630454/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/30238867/viewspace-1630454/