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 相关文章推荐
js 事件小结 表格区别
Aug 13 Javascript
点击文章内容处弹出页面代码
Oct 01 Javascript
JavaScript中的关键字"VAR"使用详解 分享
Jul 31 Javascript
jQuery检测输入的字符串包含的中英文的数量
Apr 17 Javascript
JS+CSS实现仿支付宝菜单选中效果代码
Sep 25 Javascript
JQuery+EasyUI轻松实现步骤条效果
Feb 22 Javascript
封装获取dom元素的简单实例
Jul 08 Javascript
微信小程序表单验证功能完整实例
Dec 01 Javascript
Koa 中的错误处理解析
Apr 09 Javascript
vue 使用插槽分发内容操作示例【单个插槽、具名插槽、作用域插槽】
Mar 06 Javascript
vue 使用vant插件做tabs切换和无限加载功能的实现
Nov 04 Javascript
swiperjs实现导航与tab页的联动
Dec 13 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
9个PHP开发常用功能函数小结
2011/07/15 PHP
PHP面向对象学习笔记之一 基础概念
2012/10/06 PHP
适用于抽奖程序、随机广告的PHP概率算法实例
2014/04/09 PHP
Codeigniter实现智能裁剪图片的方法
2014/06/12 PHP
Drupal简体中文语言包安装教程
2014/09/27 PHP
jQuery 树形结构的选择器
2010/02/15 Javascript
jquery中通过过滤器获取表单元素的实现代码
2011/07/05 Javascript
深入理解JavaScript系列(8) S.O.L.I.D五大原则之里氏替换原则LSP
2012/01/15 Javascript
js获取元素到文档区域document的(横向、纵向)坐标的两种方法
2013/05/17 Javascript
js 对小数加法精度处理示例说明
2013/12/27 Javascript
JqueryMobile动态生成listView并实现刷新的两种方法
2014/03/05 Javascript
js限制文本框只能输入中文的方法
2015/08/11 Javascript
jQuery地图map悬停显示省市代码分享
2015/08/20 Javascript
jQuery ui实现动感的圆角渐变网站导航菜单效果代码
2015/08/26 Javascript
JS实现状态栏跑马灯文字效果代码
2015/10/24 Javascript
jQuery+Ajax实现无刷新分页
2015/10/30 Javascript
JS实现密码框的显示密码和隐藏密码功能示例
2016/12/26 Javascript
Bootstrap jquery.twbsPagination.js动态页码分页实例代码
2017/02/20 Javascript
浅谈Vue下使用百度地图的简易方法
2018/03/23 Javascript
详解创建自定义的Angular Schematics
2018/06/06 Javascript
ant design vue中表格指定格式渲染方式
2020/10/28 Javascript
Python之Scrapy爬虫框架安装及使用详解
2017/11/16 Python
使用numpy和PIL进行简单的图像处理方法
2018/07/02 Python
python3对接mysql数据库实例详解
2019/04/30 Python
PIL对上传到Django的图片进行处理并保存的实例
2019/08/07 Python
python yield关键词案例测试
2019/10/15 Python
python安装后的目录在哪里
2020/06/21 Python
Saucony澳大利亚官网:美国跑鞋品牌,运动鞋中的劳斯莱斯
2018/05/05 全球购物
母亲节演讲稿范文
2014/01/02 职场文书
求职简历中自我评价
2014/01/28 职场文书
创业计划实施的7大步骤
2014/02/05 职场文书
授权委托书样本
2014/04/03 职场文书
党员四风剖析材料
2014/08/27 职场文书
利用Selenium添加cookie实现自动登录的示例代码(fofa)
2021/05/08 Python
为什么MySQL8新特性会修改自增主键属性
2022/04/18 MySQL
MySQL添加索引特点及优化问题
2022/07/23 MySQL