正文
由于nodejs是非阻塞单进程单线程的,一旦nodejs抛出异常,整个服务就会停掉。服务将会非常不稳定。
错误异常有两种场景的出现,
一种是代码运行中throw new error没有被捕获
另一种是Promise的失败回调函数,没有对应的reject回调函数处理
针对这两种情况Nodejs都有默认的统一处理方式,就是给整个进程process对象监听相应的错误事件。
1 | process.on('uncaughtException',function(err){ |
在有可能出现异常的地方,全部使用try { } catch(){ }
进行嵌套。
注意
一般情况下,我们会将有可能出错的代码放到
try/catch
块里。但是到了 Node.js,由于
try/catch
无法捕捉异步回调里的异常,Node.js 原生提供uncaughtException
事件挂到process
对象上,用于捕获所有未处理的异常。
处理异常的方式
总的来说处理异常有两种方式
- 同步异常用
try/catch
- 异步异常要用各自的处理方式
模拟异常
1 | // 每秒钟打印一次时间,确保程序没有奔溃 |
同步异常
try catch 方式
1 | try { |
但是try catch方式无法处理异步代码块内出现的异常,你可以理解为执行catch时,异常还没有发生。
1 | try { |
异步异常
callback方式
1 | require("fs").mkdir('G://test', function (e) { |
event方式
1 | let events = require("events"); |
Promise 方式
1 | new Promise((resolve, reject) => { |
或者
1 | new Promise((resolve, reject) => { |
Promise同样无法处理异步代码块中抛出的异常
1 | new Promise((resolve, reject) => { |
Async/Await 方式
Async是基于Promise的,可以用Await等待响应就可以用try/catch
来捕获了。
1 | var sleep = function (time) { |
所有异常
process方式
process方式可以捕获任何异常(不管是同步代码块中的异常还是异步代码块中的异常)
1 | process.on('uncaughtException', function (e) { |
Promise未捕获
1 | process.on('unhandledRejection', function (err, promise) { |
Promise中的异步错误
1 | new Promise((resolve, reject) => { |
domain方式
官方不推荐使用
https://nodejs.org/api/domain.html
https://nodejs.org/zh-cn/docs/guides/domain-postmortem/
domain模块,把处理多个不同的IO的操作作为一个组。注册事件和回调到domain,当发生一个错误事件或抛出一个错误时,domain对象会被通知,不会丢失上下文环境,也不导致程序错误立即退出,与process.on('uncaughtException')
不同。
Domain 模块可分为隐式绑定和显式绑定:
- 隐式绑定: 把在domain上下文中定义的变量,自动绑定到domain对象
- 显式绑定: 把不是在domain上下文中定义的变量,以代码的方式绑定到domain对象
方法 & 描述 | |
---|---|
1 | domain.create() 返回一个domain对象。 |
2 | domain.run(function) 在域的上下文运行提供的函数,隐式的绑定了所有的事件分发器,计时器和底层请求。 |
3 | domain.add(emitter) 显式的增加事件 |
4 | domain.remove(emitter) 删除事件。 |
5 | domain.bind(callback) 返回的函数是一个对于所提供的回调函数的包装函数。当调用这个返回的函数时,所有被抛出的错误都会被导向到这个域的 error 事件。 |
6 | domain.intercept(callback) 和 domain.bind(callback) 类似。除了捕捉被抛出的错误外,它还会拦截 Error 对象作为参数传递到这个函数。 |
7 | domain.enter() 进入一个异步调用的上下文,绑定到domain。 |
8 | domain.exit() 退出当前的domain,切换到不同的链的异步调用的上下文中。对应domain.enter()。 |
9 | domain.on(‘error’,function(err){}) 捕获的错误监听 |
process方式虽然可以捕获任何类型的异常,但是process太过笨重,除了记录下错误信息,其他地方不适合使用,domain这个也可以处理任何类型异常的模块,显然是一个不错的选择。
1 | let domain = require('domain') |
或者
1 | let d = require('domain').create(); |
express框架
express作为nodejs比较常用的框架,其实nodejs自己也有一定的异常错误捕获机制
1 | // Express errorHandler |