nodejs中错误捕获
在捕获NodeJS错误前,我们首先得知道NodeJs的错误由哪些以及怎么抛出这些错误
NodeJS的错误类型
一般来说,我们将错误简单的分为两种类型:操作错误、编码错误。
操作错误
写代码的时候都会处理一些常见的操作错误,例如JSON.parse总是会和try...catch一起,例如网络故障、远程服务器返回500等。这些错误并非bug。
处理操作错误
- 对于明确的操作错误类型,直接处理掉。
- 对于预料之外你不知道如何处理的错误,比较好的方式是记录error并crash,传递合适的错误信息给客户端。
编码错误
写代码的时候都会处理一些常见的操作错误,例如JSON.parse总是会和try...catch一起,例如网络故障、远程服务器返回500等。这些错误并非bug。
处理编码错误
最好的方式是立即crash。
NodeJS暴露错误的方式
一般通过throw、callback(err, result)错误回调函数、Event Emitter, domain暴露错误。
throw用法
throw new Error(name, message);
注意:
-
所有的erorr都使用Error对象(或者基于Error类的扩展)
-
所有的error都应该提供name和message属性,并且stack也应该准确可用。
-
使用name属性来区分错误类型
例如RangeError、TypeError。 不要为每种错误取个名字,例如定义InvalidHostnameError、InvalidIpAddressError这种来表示具体的错误,对于这种错误可以统一用InvalidArgumentError表示错误类型,然后在详细描述里补充更多信息。
示例
class InvalidArgumentError extends Error{
constructor(message) {
super();
this.name = "InvalidArgumentError";
this.message = message;
}
}
throw new InvalidArgumentError("testError");
//控制台输出
Uncaught InvalidArgumentError: testError
at <anonymous>:8:7
callback用法
一般用于异步函数对于错误处理的回调函数
callback(err, result)
EventEmitter用法
复杂场景中可以返回一个EventEmitter对象,代替使用callback。
events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。
//event.js 文件
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event', function() { //事件注册
console.log('some_event 事件触发');
});
setTimeout(function() {
event.emit('some_event'); //事件触发
}, 1000);
domain
domain和全局的异常捕获主要是为了发现和处理未预料到的编码错误 Domain(域) 简化异步代码的异常处理,可以捕捉处理try catch无法捕捉的异常。
var domain = require("domain")
domain模块,把处理多个不同的IO的操作作为一个组。注册事件和回调到domain,当发生一个错误事件或抛出一个错误时,domain对象会被通知,不会丢失上下文环境,也不导致程序错误立即退出,与process.on('uncaughtException')不同。
Domain 模块可分为隐式绑定和显式绑定:
隐式绑定: 把在domain上下文中定义的变量,自动绑定到domain对象
显式绑定: 把不是在domain上下文中定义的变量,以代码的方式绑定到domain对象
示例
var EventEmitter = require("events").EventEmitter;
var domain = require("domain");
var emitter1 = new EventEmitter();
// 创建域
var domain1 = domain.create();
domain1.on('error', function(err){
console.log("domain1 处理这个错误 ("+err.message+")");
});
// 显式绑定
domain1.add(emitter1);
emitter1.emit('error',new Error('通过监听器来处理')); // domain1 处理这个错误 (通过 domain1 处理)
var domain2 = domain.create();
domain2.on('error', function(err){
console.log("domain2 处理这个错误 ("+err.message+")");
});
// 隐式绑定
domain2.run(function(){
var emitter2 = new EventEmitter();
emitter2.emit('error',new Error('通过 domain2 处理')); // domain2 处理这个错误 (通过 domain2 处理)
});
domain1.remove(emitter1);
emitter1.emit('error', new Error('转换为异常,系统将崩溃!'));//转换为异常,系统将崩溃!
暴露错误的基本原则:
-
同步的函数里,使用throw。使用者使用try...catch即可捕获错误。
-
异步函数里,更常用的方式是使用callback(err, result)的方式。
-
在更复杂的场景里,可以返回一个EventEmitter对象,代替使用callback。使用者可以监听emitter对象的 error事件。 例如读取一个数据流,我们可能会同时使用 req.on('data')、req.on('error')、req.on('timeout') 。
-
一般用于发现和处理未预料到的编码错误。
NodeJS错误捕获的方式
- try catch
通常用于捕获throw抛出的错误
-
callback(err, result)回调函数处理
-
Emitter.on的回调函数
on注册了事件和回调函数, 并且在emit触发事件后会执行回调函数,以达到捕获错误的解决方式。
- process.on("error", function(err){})
错误异常有两种场景的出现:
一种是代码运行中throw new error没有被捕获,另一种是Promise的失败回调函数,没有对应的reject回调函数处理,针对这两种情况Nodejs都有默认的统一处理方式,就是给整个进程process对象监听相应的错误事件。
process.on('uncaughtException',function(err){}) //监听未捕获的异常
process.on('unhandledRejection',function(err,promise){}) //监听Promise没有被捕获的失败函数
- express
express作为nodejs比较常用的框架,其实nodejs自己也有一定的异常错误捕获机制
// Express' errorHandler
function errorHandler(err, req, res, next) {
console.error(err.stack);
}
app.use(errorHandler);
总结
-
区分错误类型,是可预见的还是不可避免的,是操作错误还是bug。
-
操作错误应该被处理。编码错误不应该被处理(全局处理并记录)。
3 一个函数可能产生的操作错误,只应该使用同步(throw)或者异步一种方式。一般来说,在nodejs中,同步函数导致的操作错误是比较少见的,使用try...catch会很少,常见的是用户输入验证如JSON、解析等。
-
一个函数的参数、类型、预期错误、如何捕获都应该是明确的。
-
缺少参数、参数无效都属于编码错误,应该直接抛出异常(throw)。
-
使用标准的Error类和标准属性。使用独立的属性,添加尽可能多的附加信息,尽可能使用通用的属性名称。
-
不要尝试用try...catch去捕获一个异步函数的错误,这样会什么也得不到。
8、如果不是产生错误,不要使用throw。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!