Node错误处理笔记之挖坑系列教程


Posted in Javascript onJune 05, 2018

前言

前段时间要在项目中加上日志的上报,顺势了解了下怎么在node中完善错误信息的收集。下面话不多说了,来一起看看详细的介绍吧

01 Error

 JS 中的 Error 对象,包含了错误的具体信息,包括 name、message、错误堆栈 stack 等。可以以 new Error 方式创建实例抛出,或调用 Error.captureStackTrace 为已有对象添加 stack 错误堆栈信息 而后抛出。

Node错误处理笔记之挖坑系列教程

02 错误抛出几种方式

* Throw*:Javascript 抛出的异常,是以 throw 方法抛出,未必都是 Error 的实例,但通过 nodeJs 或者 js 运行时发生的错误,都是 Error 的实例。

* EventEmitter*:Nodejs 形式的错误回调,大部分流 & 异步事件都衍生自 EventEmitter 类 || 实例,如 fs, process, stream 等。

 Process:程序运行过程中抛出的异常,或由底层库抛出,或是运行中发生的一些 SyntaxError 之类。

03 错误捕获几种方式

try .. catch:常用的一种捕获错误方式,浏览器 || node 环境均适用。

缺点:只针对同步异常有效。

Node错误处理笔记之挖坑系列教程

*EventEmitter *

由 Events 模块提供的 EventEmitter 类,基于 Observer 模式做的 publish/subscribe,通过 .on('error', ...)|| .addEventlistener('error', ...) 注册 subscriber,.emit() 发布事件,但会有最大的 maxListener 的限制,可更改。 

不 show 源码了,特别简单,自己去 look 一下。如 koa 的 app 就是基于 EventEmitter 的扩展,因此可以通过监听 error。

Node错误处理笔记之挖坑系列教程

*Process *

Process 进程对象也是 EventEmitter 的实例,可通过如下两事件监听 error。

unhandledRejection :promise 的回调报错,可通过监听该事件 catch,但要注意由于 promise 的 rejection 不知道会在啥时候才发生,所以实际上可能在 unhandledRejection 事件触发后才 catch 了这个信息,对应有 rejectionHandled 事件监听,如下:

Node错误处理笔记之挖坑系列教程

(承上)  uncaughtException  :其余 js 运行中发生 || 抛出的未捕获错误,均可通过监听该事件解决,若不进行该事件的监听,发生异常时,会直接导致程序 crash。但不建议用这种方式 catch,程序运行中的错误 更应该是抛出来,所有的 error 都 catch 的话,岂不是程序都可以看成无 bug 了。but 在打错误日志的时候是需要 catch 上报日志的,但是在上报完后,需要继续把 error throw,对于 uncaughtException callback 中抛出的异常不会再捕获,而是以非 0 的状态码 exit。

Node错误处理笔记之挖坑系列教程

04 小结

说了这么多,就做个小小总结吧  以上关系网可以概括为如图:

Node错误处理笔记之挖坑系列教程

个人见解,实际处理中基于几点准则:

1、对于需要具象化的错误信息,也就是我们需要知道具体是哪一块的错误,并且在错误发生时即进行个性化处理。这一类型的错误,在程序中执行时要对可能会出错的函数进行 catch,方式有多种:  try ... catch(同步);  或 通过 node 形式的标准错误回调 (err) => {...}(要求所调用的方法,支持该种写法);  或 监听 error 事件 .on('error', err => {...})(要求所调用的对象继承自 EventEmitter 实例,并内部发生错误时,会 emit('error'))。

2、promise 形式的错误,可在 promise 实例的末尾再引入 .catch,可捕获该实例所有 then 中抛出的异常;另外 async 的引入也允许了我们可以如同步操作一样捕获错误。

3、但有时候程序的运行,不可能针对所有的函数操作等都去 try ... catch,也不能保证程序运行一定就无 bug,但必须要能够把这些异常都捕获并上报。因此 process 的两个大 boss:  unhandledRejection & uncaughtException,是必须引入的,在程序最外层引入,且越靠前越好。此外针对 unhandledRejection,为防止说把不必要的 rejection 上报,可以在收到事件时,先把被 reject 的 promise 和 error 存储起来,设置时间 maxTimeout ,超过 maxTimeout 仍未收到 rejectionHandled 的 promise 事件,再上报。

koa 项目为例:

Node错误处理笔记之挖坑系列教程

05 源码解读

下图为 node 中对于 process 的初始化等系列流程:

Node错误处理笔记之挖坑系列教程

node.cc 其实是 node 运行主要的文件,其中定义了三个重载函数 Start,调用顺序为 3 → 2 → 1,每个函数参数不同处理不同的逻辑;

isolate->AddMessageListener 的监听事件 OnMessage 会在 js 运行发生错误时触发,嗯,是的,只有 error 才会传递 ;这很好的解释了为什么 process 监听 uncaughtException 就可以监听到所有的抛出的非 promise 异常;

OnMessage 调用了 FatalException 函数,FatalException 引用 process.fatalException 并传入 error (env 是 env.h 中声明的 Environment 类实例,fatalexceptionstring 也是其中定义的,返回值为 'fatalException');  以下为 FatalException 函数的部分内容。

Node错误处理笔记之挖坑系列教程

在调用 fatalException 函数前,先调用 v8::TryCatch::setVerbose 把 verbose 设置为 false,则运行时抛出的异常就不会再触发 FatalException ;在捕获到运行错误后,把 exitcode 设为 7,并返回;这就解释了为什么在 uncaughtException 时抛出的异常不会再重新触发回调,要知道 EventEmitter 可没帮你做这样的事情。

_fatalException 在触发 "uncaughtException" 事件前其实是会优先检查 domain 是否存在,当 domain 不存在时才会调用 uncaughtException 的,但 domain 这个已经被废除了,也就不累述了。

unhandledRejection 事件的触发整体思路也差不多,首先会调用 SetupPromises 初始化,然后调用 v8::Isolate::SetPromiseRejectCallback 进行监听 ... 并且跟 uncaughtException 不同的是 unhandledRejection 的触发只会打印 warning 并不会把整个程序给 crash 了。

06 END

参考网站:  https://v8.paulfryzel.com/docs/master/index.html

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
javascript 单选框,多选框美化代码
Aug 01 Javascript
jQuery中add实现同时选择两个id对象
Oct 22 Javascript
JavaScript将相对地址转换为绝对地址示例代码
Jul 19 Javascript
JS控制日期显示的小例子
Nov 23 Javascript
JQuery+Ajax实现数据查询、排序和分页功能
Sep 27 Javascript
jquery select2的使用心得(推荐)
Dec 04 Javascript
electron + vue项目实现打印小票功能及实现代码
Nov 25 Javascript
微信小程序模板template简单用法示例
Dec 04 Javascript
vue+vuex+json-seiver实现数据展示+分页功能
Apr 11 Javascript
jquery实现的分页显示功能示例
Aug 23 jQuery
Vue学习之axios的使用方法实例分析
Jan 06 Javascript
JavaScript将数组转换为链表的方法
Feb 16 Javascript
Vue项目中跨域问题解决方案
Jun 05 #Javascript
Vue多系统切换实现方案
Jun 05 #Javascript
jQuery实现的简单对话框拖动功能示例
Jun 05 #jQuery
vue2.0 自定义组件的方法(vue组件的封装)
Jun 05 #Javascript
vue使用技巧及vue项目中遇到的问题
Jun 04 #Javascript
jQuery实现的滑块滑动导航效果示例
Jun 04 #jQuery
jQuery实现常见的隐藏与展示列表效果示例
Jun 04 #jQuery
You might like
PHP表单提交表单名称含有点号(.)则会被转化为下划线(_)
2011/12/14 PHP
PHP序列号生成函数和字符串替换函数代码
2012/06/07 PHP
Yii2处理密码加密及验证的方法
2019/05/12 PHP
让JavaScript和其它资源并发下载的方法
2014/10/16 Javascript
javascript数组去重的六种方法汇总
2015/08/16 Javascript
jQuery Uploadify 上传插件出现Http Error 302 错误的解决办法
2015/12/12 Javascript
JavaScript类型检测之typeof 和 instanceof 的缺陷与优化
2016/01/13 Javascript
微信小程序-详解数据缓存
2016/11/24 Javascript
手机端js和html5刮刮卡效果
2020/09/29 Javascript
bootstrap table实现x-editable的行单元格编辑及解决数据Empty和支持多样式问题
2017/08/10 Javascript
vue实现消息的无缝滚动效果的示例代码
2017/12/05 Javascript
jQuery实现表格隔行换色
2018/09/01 jQuery
JavaScript数组去重的几种方法
2019/04/07 Javascript
node创建Vue项目步骤详解
2020/03/06 Javascript
JavaScript进阶(二)词法作用域与作用域链实例分析
2020/05/09 Javascript
[22:59]VGJ.S vs VG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
Python的字典和列表的使用中一些需要注意的地方
2015/04/24 Python
举例讲解Python中字典的合并值相加与异或对比
2016/06/04 Python
利用Python实现在同一网络中的本地文件共享方法
2018/06/04 Python
python实现QQ邮箱/163邮箱的邮件发送
2019/01/22 Python
提升Python程序性能的7个习惯
2019/04/14 Python
详解一种用django_cache实现分布式锁的方式
2019/09/01 Python
Python timeit模块的使用实践
2020/01/13 Python
python如何删除列为空的行
2020/07/17 Python
Jupyter Notebook添加代码自动补全功能的实现
2021/01/07 Python
Html5页面上如何禁止手机虚拟键盘弹出
2020/03/19 HTML / CSS
Myprotein丹麦官网:欧洲第一运动营养品牌
2019/04/15 全球购物
C/C++程序员常见面试题一
2012/12/08 面试题
小学语文业务学习材料
2014/06/02 职场文书
商业计算机应用专业自荐书
2014/06/09 职场文书
毕业典礼邀请函
2015/01/31 职场文书
2016学校先进集体事迹材料
2016/02/29 职场文书
如何使用Python实现一个简易的ORM模型
2021/05/12 Python
Redis缓存-序列化对象存储乱码问题的解决
2021/06/21 Redis
《艾尔登法环》Boss腐烂树灵很有可能是《黑暗之魂3》的一个废案
2022/04/11 其他游戏
vue ant design 封装弹窗表单的使用
2022/06/01 Vue.js