位置: 编程技术 - 正文

Node.js 异步异常的处理与domain模块解析(node中异步编程模式使用什么捕获异常)

编辑:rootadmin

推荐整理分享Node.js 异步异常的处理与domain模块解析(node中异步编程模式使用什么捕获异常),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:node 异步io,node中异步编程模式使用什么捕获异常,node.js异步编程,nodejs异步处理执行顺序,node中异步编程模式使用什么捕获异常,node.js异步编程,node的异步处理,nodejs异步处理执行顺序,内容如对您有帮助,希望把文章链接给更多的朋友!

异步异常处理

异步异常的特点

由于node的回调异步特性,无法通过try catch来捕捉所有的异常:

而对于web服务而言,其实是非常希望这样的:

如果try catch能够捕获所有的异常,这样我们可以在代码出现一些非预期的错误时,能够记录下错误的同时,友好的给调用者返回一个错误。可惜,try catch无法捕获异步中的异常。所以我们能做的只能是:

这个时候,虽然我们可以记录下这个错误的日志,且进程也不会异常退出,但是我们是没有办法对发现错误的请求友好返回的,只能够让它超时返回。

domain

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

于是乎,我们上面那个无奈的例子好像有了解决的方案:

我们通过中间件的形式,引入domain来处理异步中的异常。当然,domain虽然捕捉到了异常,但是还是由于异常而导致的堆栈丢失会导致内存泄漏,所以出现这种情况的时候还是需要重启这个进程的,有兴趣的同学可以去看看domain-middleware这个domain中间件。

诡异的失效

我们的测试一切正常,当正式在生产环境中使用的时候,发现domain突然失效了!它竟然没有捕获到异步中的异常,最终导致进程异常退出。经过一番排查,最后发现是由于引入了redis来存放session导致的。

此时,当我们的业务逻辑代码中出现了异常,发现竟然没有被domain捕获!经过一番尝试,终于将问题定位到了:

奇怪了!都是异步调用,为什么前者被捕获,后者却没办法捕获到呢?

Domain剖析

回过头来,我们来看看domain做了些什么来让我们捕获异步的请求(代码来自node v0..4,此部分可能正在快速变更优化)。

node事件循环机制

在看Domain的原理之前,我们先要了解一下nextTick和_tickCallback的两个方法。

上面这段代码写过node的人都很熟悉,nextTick的作用就是把laterCallback放到下一个事件循环去执行。而_tickCallback方法则是一个非公开的方法,这个方法是在当前时间循环结束之后,调用之以继续进行下一个事件循环的入口函数。

换而言之,node为事件循环维持了一个队列,nextTick入队,_tickCallback出列。

Node.js 异步异常的处理与domain模块解析(node中异步编程模式使用什么捕获异常)

domain的实现

在了解了node的事件循环机制之后,我们再来看看domain做了些什么。

domain自身其实是一个EventEmitter对象,它通过事件的方式来传递捕获的错误。这样我们在研究它的时候,就简化到两个点:

什么时候触发domain的error事件:

进程抛出了异常,没有被任何的try catch捕获到,这时候将会触发整个process的processFatal,此时如果在domain包裹之中,将会在domain上触发error事件,反之,将会在process上触发uncaughtException事件。

domain如何在多个不同的事件循环中传递:

当domain被实例化之后,我们通常会调用它的run方法(如之前在web服务中的使用),来将某个函数在这个domain示例的包裹中执行。被包裹的函数在执行的时候,process.domain这个全局变量将会被指向这个domain实例。当这个事件循环中,抛出异常调用processFatal的时候,发现process.domain存在,就会在domain上触发error事件。 在require引入domain模块之后,会重写全局的nextTick和_tickCallback,注入一些domain相关的代码:

这个是其在多个事件循环中传递domain的关键:nextTick入队的时候,记录下当前的domain,当这个被加入队列中的事件循环被_tickCallback启动执行的时候,将新的事件循环的process.domain置为之前记录的domain。这样,在被domain所包裹的代码中,不管如何调用process.nextTick, domain将会一直被传递下去。

当然,node的异步还有两种情况,一种是event形式。因此在EventEmitter的构造函数有如下代码:

实例化EventEmitter的时候,将会把这个对象和当前的domain绑定,当通过emit触发这个对象上的事件时,像_tickCallback执行的时候一样,回调函数将会重新被当前的domain包裹住。

而另一种情况,是setTimeout和setInterval,同样的,在timer的源码中,我们也可以发现这样的一句代码:

跟EventEmmiter一样,之后这些timer的回调函数也将被当前的domain包裹住了。

node通过在nextTick, timer, event三个关键的地方插入domain的代码,让它们得以在不同的事件循环中传递。

更复杂的domain

有些情况下,我们可能会遇到需要更加复杂的domain使用。

domain嵌套:我们可能会外层有domain的情况下,内层还有其他的domain,使用情景可以在文档中找到

为了实现这个功能,其实domain还会偷偷的自己维持一个domain的stack,有兴趣的童鞋可以在这里看到。

回头解决疑惑

回过头来,我们再来看刚才遇到的问题:为什么两个看上去都是同样的异步调用,却有一个domain无法捕获到异常?理解了原理之后不难想到,肯定是调用了redis的那个异步调用在抛出错误的这个事件循环内,是不在domain的范围之内的。我们通过一段更加简短的代码来看看,到底在哪里出的问题。

此时我们同样发现,错误不会被domain捕捉到,原因很清晰了:timer和e两个关键的对象在初始化的时候都时没有在domain的范围之内,因此,当在next函数中监听的事件被触发,执行抛出异常的回调函数时,其实根本就没有处于domain的包裹中,当然就不会被domain捕获到异常了!

其实node针对这种情况,专门设计了一个API:domain.add。它可以将domain之外的timer和event对象,添加到当前domain中去。对于上面那个例子:

将timer或者e任意一个对象添加到domain上,就可以让错误被domain捕获了。

再来看最开始redis导致domain无法捕捉到异常的问题。我们是不是也有办法可以解决呢?

其实对于这种情况,还是没有办法实现最佳的解决方案的。现在对于非预期的异常产生的时候,我们只能够让当前请求超时,然后让这个进程停止服务,之后重新启动。graceful模块配合cluster就可以实现这个解决方案。

__domain十分强大,但不是万能的。__希望在看过这篇文章之后,大家能够正确的使用domian,避免踩坑。

标签: node中异步编程模式使用什么捕获异常

本文链接地址:https://www.jiuchutong.com/biancheng/380773.html 转载请保留说明!

上一篇:基于Node的React图片上传组件实现实例代码(node react vue)

下一篇:Node.js安装配置图文教程(node.js的安装步骤)

  • 专项应付款怎核算?
  • 工程劳务费计入哪个会计科目
  • 负数发票可以作废不
  • 单位之间调动
  • 机票抵进项税税率
  • 小规模纳税人处置固定资产的税率
  • 摊销折旧是什么意思
  • 二手房怎么避免一房多卖
  • 房屋租赁费如何计提
  • 小规模跨年发票可以入账吗
  • 库存商品结转成本的金额怎么计算
  • 交易性金融资产借贷方向
  • 小规模和一般纳税人的区别
  • 个人去税务局开劳务费税率
  • 缺联发票税务怎么处理
  • 税务局拍卖资产
  • 代开专票退票流程及说明
  • 公司费用种类
  • 转让公司账本凭证都要移交吗
  • 产品检测费用计入什么科目
  • 赠送样品需要交税吗
  • 在建工程暂估入库的账务处理
  • 红字发票如果开多了下个月能进行抵扣么?
  • 信汇凭证是转账凭证吗
  • 小规模纳税人计提增值税账务处理
  • 姑娘果的功效与作用百度百科
  • 收到违反合同的违约金
  • 销售净利率的计算公式有哪些
  • 老板的工资属于
  • msoobe.exe是什么
  • 增值税有哪些类型的税种
  • PHP:mcrypt_module_is_block_algorithm_mode()的用法_Mcrypt函数
  • 递延所得税资产和负债怎么理解
  • php替换文本指定内容
  • vue中过滤器有什么作用及详解
  • 差旅费报销应注意什么
  • Vue3通透教程【二】更高效的构建工具—Vite
  • 长期股权投资成本怎么计算
  • 已认证的发票
  • 资金账簿印花税怎么算
  • 增值税进项发票不够抵扣怎么办
  • 待报解啥意思
  • 小规模减免的增值税
  • 如何查询工商局每天入驻情况
  • 怎么计算土地增值税收入
  • 减免增值税的相关规定
  • 不动产租赁行业代码
  • 受托方受托代销商品会计分录
  • 收到支付宝认证怎么做账
  • 公司给的佣金需要上多少税
  • 借款怎么收回来
  • 政府会计制度累计盈余为负数
  • 银行存款日记账与银行对账单之间的核对属于
  • 一般纳税人印花税税率是多少
  • 事业单位收费可以收取相关服务费吗
  • 子公司和区域公司的区别
  • 贷款购车怎么做会计分录
  • sql server 数据库介绍
  • 该卡已在其他账户中存在什么意思
  • 阿里云linux 服务器 字符集
  • 联想笔记本在bios关闭触摸板
  • win8系统连接vpn失败提示错误代码807的解决方法
  • win10启动项怎么设置
  • win10右键菜单怎么设置
  • win7系统电脑屏幕倒过来了怎么办
  • xp系统做完了进不去
  • win7系统误删文件可以恢复吗
  • 平板电脑安装的是什么格式的软件
  • opengl详解
  • android打包v1v2
  • 怎么在dos下运行
  • windows常用网络命令的使用
  • 2020 unity
  • nodejs tcp
  • Python简单格式化时间的方法【strftime函数】
  • 税务稽查时长
  • 个人所得税税单下载
  • 湖南省株洲市税务局
  • 税务局发票邮寄费用谁承担
  • 2021年河南医保
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设