和其他服务器端语言相比,貌似node.js 对于异常捕捉确实非常困难.

首先你会想到try/catch ,但是在使用过程中我们会发现并没有真正将错误控制在try/catch 语句中.

为什么?

答案是这样的:

node.js 是异步IO执行,所以我们将try/catch 反正异步回调函数中,当出现一个异常的时候,我们try 拿到这个错误时应该错过了当前程序运行堆栈,

而在node.js原生的uncaughtException 处理事件却挂在 process 对象上,OMG,你可想而知,如果一个异常出现时,当前运行的 process 会直接挂掉,

导致错误永远不会走到 catch 语句.所以 try/catch 在异步回调中显得苍白无力,我们有什么办法控制这种异步回调的异常吗?

当然,我们下面来介绍一种比较有效的处理方法:

domain模块,这是node自带的一个模块,看名字确实很难联想到他是用来捕捉异常的,它能帮我们做一些try /catch无法做到的事情.

首先引用模块

var domain = require('domain');

如果你也使用Express框架,可以直接将domain 做成一个 Express 的中间件,这样所有的 request及response 中的异步错误都可以捕捉到.

app.configure(function () {
    app.use(function (req, res, next) {
        var reqDomain = domain.create();
        reqDomain.on('error', function (err) {  // 下面抛出的异常在这里被捕获,触发此事件
            console.log('捕获到错误');
            res.send(500, err.stack);           // 成功给用户返回了 500
        });
        reqDomain.run(next);
    });
});

上面这种写法是Express 的一个中间件写法, app.use(function(req,res,next){  .....}) 这是一个中间件,用来接收所有http请求,这里你可以捕获request 和 response 对象用来做一些过滤,逻辑判断等等,最后通过 next 来放行本次请求,那么这个中间件就完成了他的一次使命.

而我们为了让 domain 模块来接管所有的http请求中的异常,所以把它写成一个中间件是非常方便的.

然后我们在 process 上将未处理的异常捕捉一下,做到万无一失.

process.on('uncaughtException', function (err) {
    console.error("uncaughtException ERROR");
    if (typeof err === 'object') {
        if (err.message) {
            console.error('ERROR: ' + err.message)
        }
        if (err.stack) {
            console.error(err.stack);
        }
    } else {
        console.error('argument is not an object');
    }
});

//下面我们来定义几个路由,测试一下.

app.get('/', function (req, res) {
    levelDB.getData('test', function (err, v) {
        //这里我从levelDB 中读取一条数据,需要引入 levelDB 模块.
        err ? res.send({status: "fail"}) : res.send({status: "success", value: v});
    });
})

//我们再想办法让程序出现一个异步异常

app.get('/err', function (req, res) {
    //throw new Error('exception'); 
    setTimeout(function () {
        throw new Error('exception'); // 抛出一个异步异常
    }, 1000);
})

//我们之所以想到用 setTimeout 就是想模拟一个异步的回调,如果你直接 throw new Error('exception');这样就不是异步了,直接会被 process 上的 uncaughtException 来接管.

通过上面定义的两个路由,我们来分别访问一下

这个路由我们从数据库读取了一条记录最后返回给客户端,中间没有出现任何异常.

这是我们模拟的一个异常已经被捕捉到,这是服务器端返回给客户端的一个500提示信息,这时我们再看一眼控制台,node 进程并没有挂掉.

每次 domian 捕获到错误后,我都在控制台输出了一行提示信息 "捕获到错误" 当前进程并没有因为异常而挂掉,这就是我们要的效果.

使用domain模块捕获异步回调中的异常的更多相关文章

  1. node.js 使用domain模块捕获异步回调中的异常

    和其他服务器端语言相比,貌似node.js 对于异常捕捉确实非常困难. 首先你会想到try/catch ,但是在使用过程中我们会发现并没有真正将错误控制在try/catch 语句中. 为什么? 答案是 ...

  2. Android异步回调中的UI同步性问题

    Android程序编码过程中,回调无处不在.从最常见的Activity生命周期回调开始,到BroadcastReceiver.Service以及Sqlite等.Activity.BroadcastRe ...

  3. [置顶] Ajax程序:处理异步调用中的异常(使用Asp.Net Ajax内建的异常处理方法)

    无论在Window应用程序,还是Web应用程序以对用户友好的方式显示运行时的异常都是很有必要,尤其对于可能有很多不确定因素导致异常的Web应用程序;在传统的Web开发中,处理异常的方式——设计专门一个 ...

  4. js即时函数在异步回调中的运用

    在编程中我们会接触到循环和异步编程的情况,这时异步回调执行逻辑就会出现问题.我们用setTimeout来模拟异步的: for(var i=0;i<3;i++){ setTimeout(funct ...

  5. java主线程捕获子线程中的异常

    本文主要参考:<think in java> 好,下面上货. 正常情况下,如果不做特殊的处理,在主线程中是不能够捕获到子线程中的异常的. 例如下面的情况. package com.xuey ...

  6. 在异步回调中调用MessageBox.Show

    public static void Test() { ThreadStart aThreadStart = delegate() { ); MessageBox.Show("Good!&q ...

  7. 【转】asp.net 利用Global.asax 捕获整个解决方案中的异常错误

    之前做项目的时候都是在每个页面中处理这不同的异常信息,一个页面数下来,很多个try{}catch{}语句块,令整个代码结构有些不够美观. 今天看到一篇帖子,是关于利用全局应用程序类来帮忙获取异常信息, ...

  8. MVC与WebApi中的异常过滤器

    一.MVC的异常过滤器   1.自定义MVC异常过滤器 创建一个类,继承HandleErrorAttribute即可,如果不需要作为特性使用直接实现IExceptionFilter接口即可, 注意,该 ...

  9. 如何优雅的处理Nodejs中的异步回调

    前言 Nodejs最大的亮点就在于事件驱动, 非阻塞I/O 模型,这使得Nodejs具有很强的并发处理能力,非常适合编写网络应用.在Nodejs中大部分的I/O操作几乎都是异步的,也就是我们处理I/O ...

随机推荐

  1. python替换脚本

    任何场合都用的到的全文替换 #!/usr/bin/python import sys if len(sys.argv) < 5: print 'usage: python %s from to ...

  2. NLP︱高级词向量表达(二)——FastText(简述、学习笔记)

    FastText是Facebook开发的一款快速文本分类器,提供简单而高效的文本分类和表征学习的方法,不过这个项目其实是有两部分组成的,一部分是这篇文章介绍的 fastText 文本分类(paper: ...

  3. Android HTTP请求用HttpUrlConnection与HttpClient比较

    在安卓和JAVA应用开发中需要访问网络,少不了要提交HTTP请求,而基本上目前有两个实现方式:HttpUrlConnection(即URL.openConnection)和HttpClient. 网上 ...

  4. JSP标签c:forEach报错(二)

    1.今天,我在用c标签写一些样例,结果出现一些错误,写下作为记录 具体错误如下: 三月 31, 2014 9:46:28 下午 org.apache.catalina.core.StandardWra ...

  5. Excel 2010高级应用-折线图(二)

    在Excel中画折线图,具体操作过程如下: 1.新建一个excel文件,双击打开 2.单击"插入",找到折线图,单击下拉框 3.在折线框下方,新建数据源 4.鼠标右键,选择&quo ...

  6. Tea HDU - 5881

    Tea is good. Tea is life. Tea is everything. The balance of tea is a journey of pursuing balance of ...

  7. ontimer 与多线程

    一般来说,在MFC中开启一个UI线程可以用以下代码: m_pCameraThread = AfxBeginThread(RUNTIME_CLASS(CCameraThread)); if (!m_pC ...

  8. Python基础_文件的的处理及异常处理

    今天主要讲讲文件读写及异常处理. 一.文件操作 1.1 文件的创建及读 打开文件 open 函数  open(file,[option]) file 是要打开的文件 option是可选择的参数文件的打 ...

  9. RobotFramework下HttpLibrary库其它关键字

    关键字 使用描述 DELETE 向服务器端发送http delete请求,该请求接收一个参数[ url ],请求的方式和post请求非常类似,示例: DELETE /_utils/config.htm ...

  10. SpringBoot集成Shiro并用MongoDB做Session存储

    之前项目鉴权一直使用的Shiro,那是在Spring MVC里面使用的比较多,而且都是用XML来配置,用Shiro来做权限控制相对比较简单而且成熟,而且我一直都把Shiro的session放在mong ...