Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 391|回复: 0

Nodejs异步异常处理domain

[复制链接]
  • TA的每日心情
    奋斗
    4 天前
  • 签到天数: 802 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726006
    发表于 2021-5-26 06:19:52 | 显示全部楼层 |阅读模式

    前言

    程序开发中,最麻烦的事情之一就是异常处理;对于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() * 10;
        console.log("random num is " + r);
        if (r > 5) {
            throw new Error("Error: random num" + r + " > 5");
        }
    }
    
    setInterval(function () {
        try {
            sync_error();
        } catch (err) {
            console.log(err);
        }
    
    }, 1000)

     

    运行程序

    ~ D:\workspace\javascript\nodejs-domain>node sync.js
    random num is 1.067440479528159
    random num is 6.284254263155162
    [Error: Error: random num6.284254263155162 > 5]
    random num is 8.445568478200585
    [Error: Error: random num8.445568478200585 > 5]
    random num is 2.79862868366763
    random num is 5.452311446424574
    [Error: Error: random num5.452311446424574 > 5]
    random num is 3.725348354782909
    random num is 7.590636070817709
    [Error: Error: random num7.590636070817709 > 5]
    random num is 9.584896392188966
    [Error: Error: random num9.584896392188966 > 5]
    random num is 3.63708304008469
    random num is 5.747077965643257
    [Error: Error: random num5.747077965643257 > 5]
    random num is 1.0771577199921012
    random num is 8.898805833887309
    [Error: Error: random num8.898805833887309 > 5]
    random num is 6.59792885184288
    [Error: Error: random num6.59792885184288 > 5]
    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() * 10;
            console.log("random num is " + r);
            if (r > 5) {
                throw new Error("Error: random num" + r + " > 5");
            }
        },10)
    
    }
    
    setInterval(function () {
        try {
            async_error();
        } catch (err) {
            console.log(err);
        }
    }, 1000)

     

    运行程序

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

     

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

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

    ~ vi async.js
    
    function async_error() {
        setTimeout(function(){
            var r = Math.random() * 10;
            console.log("random num is " + r);
            if (r > 5) {
                throw new Error("Error: random num" + r + " > 5");
            }
        },10)
    
    }
    
    setInterval(function () {
        try {
            async_error();
        } catch (err) {
            console.log(err);
        }
    }, 1000)
    
    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.33843155624345 > 5]
    random num is 7.894433259498328
    [Error: Error: random num7.894433259498328 > 5]
    random num is 2.532815719023347
    random num is 6.0961083066649735
    [Error: Error: random num6.0961083066649735 > 5]
    random num is 5.138748907484114
    [Error: Error: random num5.138748907484114 > 5]

    通过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() * 10;
        console.log("sync num is " + r);
        if (r > 5) {
            throw new Error("sync: random num" + r + " > 5");
        }
    }
    
    function async_error() {
        setTimeout(function(){
            var r = Math.random() * 10;
            console.log("async num is " + r);
            if (r > 5) {
                throw new Error("async: random num" + r + " > 5");
            }
        },10)
    
    }
    
    var d = domain.create();
    d.on('error',function(err){
        console.log(err);
    });
    
    setInterval(function () {
        d.run(sync_error);
        d.run(async_error);
    }, 1000)

     

    运行程序

    ~ D:\workspace\javascript\nodejs-domain>node domain.js
    sync num is 8.492766928393394
    { [Error: sync: random num8.492766928393394 > 5]
      domain:
       { domain: null,
         _events: { error: [Function] },
         _maxListeners: 10,
         members: [] },
      domainThrown: true }
    sync num is 4.991524459328502
    async num is 7.5735537661239505
    { [Error: async: random num7.5735537661239505 > 5]
      domain:
       { domain: null,
         _events: { error: [Function] },
         _maxListeners: 10,
         members: [] },
      domainThrown: true }
    sync num is 4.626072463579476
    async num is 9.48660139227286
    { [Error: async: random num9.48660139227286 > 5]
      domain:
       { domain: null,
         _events: { error: [Function] },
         _maxListeners: 10,
         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.712894310243428 > 5]
      domain:
       { domain: null,
         _events: { error: [Function] },
         _maxListeners: 10,
         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');
    }, 10);
    
    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:12
            throw new Error('Receive data error!');
                  ^
    Error: Receive data error!
        at EventEmitter. (D:\workspace\javascript\nodejs-domain\special.js:12:15)
        at EventEmitter.g (events.js:175:14)
        at EventEmitter.emit (events.js:92:17)
        at null._onTimeout (D:\workspace\javascript\nodejs-domain\special.js:7:7)
        at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)

    如果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');
    }, 10);
    
    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: 10,
         members: [ [Object], [Object] ] },
      domainThrown: true }

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

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

     

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

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-11-15 16:00 , Processed in 1.114206 second(s), 28 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表