代码改变世界

NodeJS之异常处理

2019-03-25 23:22  龙恩0707  阅读(8043)  评论(1编辑  收藏  举报

1. 为什么要处理异常?

如果我们不处理异常的话,直接会导致程序奔溃,用户体验比较差,因此我们要对异常进行处理,当出现异常的情况下,我们要给用户一个友好的提示,并且记录该异常,方便我们排查。

2. 在Node.js中常用的异常处理方式有哪些?

2.1 使用try catch方式来处理异常,如下代码:

try {
  throw new Error('error');
} catch(e) {
  console.log('异常被捕获了,我现在还可以继续执行了');
  console.log(e);
}

然后执行命令行时候,可以看到如下,也会打印后面的 console.log的信息了;如下所示:

但是使用 try catch 无法处理异步代码块内出现的异常,比如如下代码:

try {
  setTimeout(() => {
    throw new Error('error');
  })
} catch(e) {
  console.log('异常被捕获了,我现在还可以继续执行了');
  console.log(e);
}

在命令行中打印信息如下:

可以看到,catch里面的console.log(''); 代码并没有被执行。说明catch里面的代码异常并没有被捕获到。

2.2 使用event方式来处理异常

const events = require('events');

// 创建一个事件监听对象
const emitter = new events.EventEmitter();

// 监听error事件
emitter.addListener('error', (e) => {
  // 处理异常信息
  console.log(11122222); // 能打印 1112222 说明异常捕获到了
  console.log(e);
});

// 触发 error事件
emitter.emit('error', new Error('你代码出错了'));

执行效果如下图所示:

2.3 callback的方式

比如读取一个文件,或者创建一个目录,测试代码如下:

const fs = require('fs');

fs.mkdir('/dir', (e) => {
  if (e) {
    console.log('异常信息处理');
    console.log(e);
  } else {
    console.log('创建目录成功');
  }
});

然后执行结果如下图所示:

2.4 Promise方式

new Promise((resolve, reject) => {
  throw new Error('error');
}).then(() => {
  // 。。。。
}).catch((e) => {
  console.log('能进来说明可以处理异常信息了');
  console.log(e);
});

执行结果如下图所示:

如上是处理同步代码,但是如果是异步代码呢?继续如下代码测试:

new Promise((resolve, reject) => {
  setTimeout(() => {
    throw new Error('error');
  }, 100);
}).then(() => {
  // 。。。。
}).catch((e) => {
  console.log('能进来说明可以处理异常信息了');
  console.log(e);
});

然后执行结果如下所示:

可以看到,Promise也是一样无法捕获异步代码中的异常信息了。

2.5 Async/Await 方式

Async/Await 也是基于Promise的,Promise是无法捕获异步异常,因此Async/Await 也是没有办法捕获的。如下测试代码:

先看同步代码可以捕获到的,代码如下:

const testFunc = function() {
  return new Promise((resolve, reject) => {
    throw new Error('error');
  });
};

async function testAsync() {
  try {
    await testFunc();
  } catch (e) {
    console.log('能进来,说明异常能处理');
    console.log(e);
  }
}

testAsync();

执行结果如下所示:

我们再看异步代码,如下所示:

const testFunc = function() {
  setTimeout(() => {
    console.log(1111);
    return new Promise((resolve, reject) => {
      throw new Error('error');
    });
  }, 100);
};

async function testAsync() {
  try {
    await testFunc();
  } catch (e) {
    console.log('能进来,说明异常能处理');
    console.log(e);
  }
}

testAsync();

如下图所示:

2.6 process 方式(该方式既可以处理同步代码的异常,也可以处理异步代码的异常)。

如下同步代码异常:

process.on('uncaughtException', (e) => {
  console.log('我能进来,说明可以处理异常');
  console.log(e);
});

function testFunc() {
  throw new Error('error');
}

testFunc();

执行结果如下所示:

异步代码如下所示:

process.on('uncaughtException', (e) => {
  console.log('我能进来,说明可以处理异常');
  console.log(e);
});

function testFunc() {
  setTimeout(() => {
    throw new Error('error');
  }, 100);
}

testFunc();

如下图所示:

2.7 domain 方式

domain也可以处理任何类型异常的信息,包含同步和异步。

如下同步代码所示:

const domain = require('domain');
const d = domain.create();

d.on('error', (e) => {
  console.log('我能进来,说明能处理异常');
  console.log(e);
});

d.run(() => {
  throw new Error('同步代码处理');
});

如下图所示:

异步代码如下所示:

const domain = require('domain');
const d = domain.create();

d.on('error', (e) => {
  console.log('我能进来,说明能处理异常');
  console.log(e);
});

d.run(() => {
  setTimeout(() => {
    throw new Error('异步代码处理');
  }, 100);
});

如下图所示: