前言

程序开发中,最麻烦的事情之一就是异常处理;对于Nodejs程序开发,最麻烦的事情莫过于异步异常处理。

以MVC的多层架构设计角度,异常总是要一层一层向上抛出,最后在客户端出打印错误。但是,Nodejs都是异步异常,try..catch根本就捕捉不到,就会给我们的程序设计带来不小的麻烦,经常会有未处理的runtime异常,让整个系统挂掉。

目录

  1. Nodejs异常处理
  2. Nodejs异步异常处理
  3. domain介绍
  4. domain的API介绍
  5. domain异步异常特例

1. Nodejs同步异常处理

系统环境

  • win7 64bit
  • Nodejs:v0.10.5
  • Npm:1.2.19

创建项目

~ D:\workspace\javascript>mkdir nodejs-domain && cd nodejs-domain

新建文件:sync.js,模拟同步异常的处理

~ vi sync.js

function sync_error() {
var r = Math.random() * ;
console.log("random num is " + r);
if (r > ) {
throw new Error("Error: random num" + r + " > 5");
}
} setInterval(function () {
try {
sync_error();
} catch (err) {
console.log(err);
} }, )

运行程序

~ D:\workspace\javascript\nodejs-domain>node sync.js
random num is 1.067440479528159
random num is 6.284254263155162
[Error: Error: random num6. > ]
random num is 8.445568478200585
[Error: Error: random num8. > ]
random num is 2.79862868366763
random num is 5.452311446424574
[Error: Error: random num5. > ]
random num is 3.725348354782909
random num is 7.590636070817709
[Error: Error: random num7. > ]
random num is 9.584896392188966
[Error: Error: random num9. > ]
random num is 3.63708304008469
random num is 5.747077965643257
[Error: Error: random num5. > ]
random num is 1.0771577199921012
random num is 8.898805833887309
[Error: Error: random num8. > ]
random num is 6.59792885184288
[Error: Error: random num6. > ]
random num is 1.8532328261062503
random num is 3.6028534593060613
random num is 2.7523675211705267
random num is 1.598257850855589

通过try..catch可以很好的抓到同步程序的异常。

2. Nodejs异步异常处理

新建文件:async.js,模拟异步异常处理

~ vi async.js

function async_error() {
setTimeout(function(){
var r = Math.random() * ;
console.log("random num is " + r);
if (r > ) {
throw new Error("Error: random num" + r + " > 5");
}
},) } setInterval(function () {
try {
async_error();
} catch (err) {
console.log(err);
}
}, )

运行程序

~ D:\workspace\javascript\nodejs-domain\sync.js:
throw new Error("Error: random num" + r + " > 5");
^
Error: Error: random num9. >
at trycatch (D:\workspace\javascript\nodejs-domain\sync.js::)
at Timer. (D:\workspace\javascript\nodejs-domain\sync.js::)
at Timer.timer.ontimeout (timers.js::)

try..catch,无法捕捉异步异常!

修改async.js, 通过process.on()打印错误信息。

~ vi async.js

function async_error() {
setTimeout(function(){
var r = Math.random() * ;
console.log("random num is " + r);
if (r > ) {
throw new Error("Error: random num" + r + " > 5");
}
},) } setInterval(function () {
try {
async_error();
} catch (err) {
console.log(err);
}
}, ) process.on('uncaughtException', function (err) {
console.log(err);
});

运行程序

~ D:\workspace\javascript\nodejs-domain>node async.js
random num is 9.33843155624345
[Error: Error: random num9. > ]
random num is 7.894433259498328
[Error: Error: random num7. > ]
random num is 2.532815719023347
random num is 6.0961083066649735
[Error: Error: random num6. > ]
random num is 5.138748907484114
[Error: Error: random num5. > ]

通过process.on(‘uncaughtException’)的内置函数,虽然我们可以记录下这个错误的日志,而且进程也不会异常退出,但是我们是没有办法对发现错误的请求友好返回的,只能够让它超时返回。

3. domain介绍

node在v0.8+版本的时候,发布了一个模块domain。这个模块做的就是try catch所无法做到的:捕捉异步回调中出现的异常。

domain模块,把处理多个不同的IO的操作作为一个组。注册事件和回调到domain,当发生一个错误事件或抛出一个错误时,domain对象 会被通知,不会丢失上下文环境,也不导致程序错误立即推出,与process.on(‘uncaughtException’)不同。

domain的发布页http://nodejs.org/api/domain.html

用domain捕捉异常,新建文件domain.js

~ vi domain.js

var domain = require('domain');

function sync_error() {
var r = Math.random() * ;
console.log("sync num is " + r);
if (r > ) {
throw new Error("sync: random num" + r + " > 5");
}
} function async_error() {
setTimeout(function(){
var r = Math.random() * ;
console.log("async num is " + r);
if (r > ) {
throw new Error("async: random num" + r + " > 5");
}
},) } var d = domain.create();
d.on('error',function(err){
console.log(err);
}); setInterval(function () {
d.run(sync_error);
d.run(async_error);
}, )

运行程序

~ D:\workspace\javascript\nodejs-domain>node domain.js
sync num is 8.492766928393394
{ [Error: sync: random num8. > ]
domain:
{ domain: null,
_events: { error: [Function] },
_maxListeners: ,
members: [] },
domainThrown: true }
sync num is 4.991524459328502
async num is 7.5735537661239505
{ [Error: async: random num7. > ]
domain:
{ domain: null,
_events: { error: [Function] },
_maxListeners: ,
members: [] },
domainThrown: true }
sync num is 4.626072463579476
async num is 9.48660139227286
{ [Error: async: random num9. > ]
domain:
{ domain: null,
_events: { error: [Function] },
_maxListeners: ,
members: [] },
domainThrown: true }
sync num is 2.3057156521826982
async num is 4.5645097037777305
sync num is 2.0251641585491598
async num is 7.712894310243428
{ [Error: async: random num7. > ]
domain:
{ domain: null,
_events: { error: [Function] },
_maxListeners: ,
members: [] },
domainThrown: true }

我们发现domain,可以同时捕捉到同步异常(sync)和异步异常(async)。

4. domain的API介绍

基本概念

  • 隐式绑定: 把在domain上下文中定义的变量,自动绑定到domain对象
  • 显式绑定: 把不是在domain上下文中定义的变量,以代码的方式绑定到domain对象

API介绍

  • domain.create(): 返回一个domain对象
  • domain.run(fn): 在domain上下文中执行一个函数,并隐式绑定所有事件,定时器和低级的请求。
  • domain.members: 已加入domain对象的域定时器和事件发射器的数组。
  • domain.add(emitter): 显式的增加事件
  • domain.remove(emitter): 删除事件
  • domain.bind(callback): 以return为封装callback函数
  • domain.intercept(callback): 同domain.bind,但只返回第一个参数
  • domain.enter(): 进入一个异步调用的上下文,绑定到domain
  • domain.exit(): 退出当前的domain,切换到不同的链的异步调用的上下文中。对应domain.enter()
  • domain.dispose(): 释放一个domain对象,让node进程回收这部分资源

5. domain异步异常特例

下面这个例子,domain将捕捉不到异步异常

var domain = require('domain');
var EventEmitter = require('events').EventEmitter; var e = new EventEmitter(); var timer = setTimeout(function () {
e.emit('data');
}, ); function next() {
e.once('data', function () {
throw new Error('Receive data error!');
});
} var d = domain.create();
d.on('error', function (err) {
console.log(err);
}); d.run(next);

运行程序

~ D:\workspace\javascript\nodejs-domain\special.js:
throw new Error('Receive data error!');
^
Error: Receive data error!
at EventEmitter. (D:\workspace\javascript\nodejs-domain\special.js::)
at EventEmitter.g (events.js::)
at EventEmitter.emit (events.js::)
at null._onTimeout (D:\workspace\javascript\nodejs-domain\special.js::)
at Timer.listOnTimeout [as ontimeout] (timers.js::)

如果timer和e两个关键的对象在初始化的时候都时没有在domain的范围之内,因此,当在next函数中监听的事件被触发,执行抛出异常的回调函数时,其实根本就没有处于domain的包裹中,就不会被domain捕获到异常了!

修改程序代码

var domain = require('domain');
var EventEmitter = require('events').EventEmitter; var e = new EventEmitter(); var timer = setTimeout(function () {
e.emit('data');
}, ); function next() {
e.once('data', function () {
throw new Error('Receive data error!');
});
} var d = domain.create();
d.on('error', function (err) {
console.log(err);
}); d.add(e);
d.add(timer); d.run(next);

增加e和timer到domain的范围内,运行程序

~ D:\workspace\javascript\nodejs-domain>node special.js
{ [Error: Receive data error!]
domain:
{ domain: null,
_events: { error: [Function] },
_maxListeners: ,
members: [ [Object], [Object] ] },
domainThrown: true }

domain特例代码摘自:http://cnodejs.org/topic/516b64596d38277306407936

通过domain模块,我们就可以好好设计Nodejs系统的异常管理了。

文章转载自:http://blog.fens.me/nodejs-core-domain/ ‎   看到不错的文章,自己又能看懂的果断转载,学习并收录下,o(∩_∩)o

Nodejs异步异常处理domain的更多相关文章

  1. Node.js之路【第三篇】NodeJS异步实现

    NodeJS异步实现 Node.js异步编程的直接体现就是回调,它依托于回调来实现,但不能说使用了回调他就是异步了 回调函数在完成任务后就会被调用,Node使用了大量的回调函数,Node所有的API都 ...

  2. NodeJS异步I/O解析

    在现在的项目开发中,任何一个大型项目绝对不是简简单单的采用一个种语言和一种框架,因为每种语言和框架各有优势,与其死守一个,不与取各家之所长,依次得到一个高性能.搞扩展的产品. 对于一个.NET开发者, ...

  3. NodeJS之异常处理

    1. 为什么要处理异常? 如果我们不处理异常的话,直接会导致程序奔溃,用户体验比较差,因此我们要对异常进行处理,当出现异常的情况下,我们要给用户一个友好的提示,并且记录该异常,方便我们排查. 2. 在 ...

  4. (一)Nodejs - 框架类库 - Nodejs异步流程控制Async

    简介 Async是一个流程控制工具包,提供了直接而强大的异步功能 应用场景 业务流程逻辑复杂,适应异步编程,减少回调的嵌套 安装 npm insatll async 函数介绍 Collections ...

  5. 深入浅出NodeJS——异步I/O

    底层操作系统,异步通过信号量.消息等方式有着广泛的应用. PHP语言从头到尾都是以同步堵塞方式执行,利于程序猿顺序编写业务逻辑. 异步I/O.事件驱动.单线程构成Node的基调. why异步I/O ( ...

  6. nodejs异步转同步

    项目在微信环境开发,需要获取access_token进行授权登录和获取用户信息. 特意把这块功能拿出来封装一个自定义module module.exports = new Wechat(con.app ...

  7. nodejs异步调用async

    犹豫nodejs是异步编程模型,有一些在同步编程中很容易做到的事情,现在却变得很麻烦,async的流程控制就是为了简化这些操作var async = require('async'); 1.serie ...

  8. 20121124.Nodejs异步式I/O与事件式编程

    异步: 你请人吃饭,准备一起去的.结果那人刚好有事,让你先去点菜,你去点好菜,他忙完就来了,这就是异步的优势(不耽误事!)同步: 就是,你必须等那个人忙完了,才一起去(浪费时间) 理解来源于群友&qu ...

  9. nodejs异步处理

    采用Async.Q.Promise等第三方库处理异步回调 Async 安装 npm install async --save-dev

随机推荐

  1. SQL疑难杂症【1】解决SQL2008 RESTORE 失败问题

    有时候从服务器或者其它电脑上面备份的数据库文件在还原到本地的时候会出现以下错误:  这种情况通常是备份文件之前的逻辑名称跟当前的名称对应不上,我们可以通过以下语句查看备份文件的逻辑名称: 知道备份文件 ...

  2. 软/硬链接指令:ln

    语法: ln  [选项]  原文件  目标文件 选项: -s 创建软连接(创建软链接时,若所在文件夹不一致,原文件要使用绝对路径) 硬链接特征: 1.拥有相同i节点和存储block块,可以看成是同一个 ...

  3. poj 1106 Transmitters (叉乘的应用)

    http://poj.org/problem?id=1106 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4488   A ...

  4. linux 命令行模式下,浏览网页

    Ubuntu自带最新版的Gnome桌面,拥有大量的服务和桌面应用程序,让您仅通过一张安装光盘就可以体验到无比舒适的操作环境.下文介绍的在ubuntu下使用终端命令行上网的方法. 第一步,需要安装一个名 ...

  5. tiled工具使用

    转的 在这个分为上下两部分的教程中,我们将介绍如何使用Cocos2D-X和地图编辑器做一款基于地图块的游戏.在这个简单的地图块游戏里,一个精灵将在沙漠里搜寻它可口的西瓜! 在教程的第一部分,我们将介绍 ...

  6. html中出现的script失效

    如果在Controller中出现script代码类似 $hello_str='Hello God<script>alert(3);</script>'; 那么我不希望在传给vi ...

  7. Linux内核访问外设I/O--动态映射(ioremap)和静态映射(map_desc) (转载)

    [转](转)Linux内核访问外设I/O资源的方式-静态映射(map_desc)方式 Linux内核访问外设I/O资源的方式 Author: Dongas Date: 08-08-02 我们知道默认外 ...

  8. JavaWeb学习总结(三)—Servlet

    1. 什么是Servlet * Servlet是JavaWeb三大组件之一(Servlet.Filter.Listener) ,Servlet是用来处理客户端请求的动态资源,按照一种约定俗成的称呼习惯 ...

  9. (十)Linux内核中的常用宏container_of

    Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...

  10. Nginx 启用gzip压缩

    1. 网页压缩 网页压缩是一项由 WEB 服务器和浏览器之间共同遵守的协议,也就是说 WEB 服务器和浏览器都必须支持该技术,所幸的是现在流行的浏览器都是支持的,包括 IE.FireFox.Opera ...