Node.js异常捕获处理

本文介绍了Node.js的异常特点,强调其在异步单线程模型中异常处理的特殊性。同步异常通常使用try...catch处理,而异步异常可通过callback、EventEmitter的error事件、Promise和async/await的catch方法捕获。特别地,当出现uncaughtException事件时,应谨慎处理并避免继续执行可能导致不稳定的操作,而是进行资源清理后退出进程。

Node.js异常特点

Node.js异步单线程模型对于异常捕获处理影响:
异步:Node.js异常不只可能出现在同步代码中,也可能出现在异步代码中,而异步异常捕获处理方式有别于同步异常。
单线程:如果不捕获处理程序运行时发生的异常,应用进程将因为异常而立即退出。

异常的捕获处理

同步异常

JavaScript 语言提供的 try…catch 语句处理

// 抛出一个 ReferenceError,因为 z 未定义。
try {
  const m = 1;
  const n = m + z;
} catch (err) {
  // 在这里处理错误。
  console.error(err); // ReferenceError: z is not defined
}

所有 JavaScript 错误都会被作为异常处理,异常会立即产生并使用标准的 JavaScript throw 机制抛出一个错误。JavaScript 的 throw 机制的任何使用都会引起异常,必须使用 try…catch 处理,否则 Node.js 进程会立即退出。Node.js少数例外的同步的 API(任何不接受 callback 函数的阻塞方法,例如 fs.readFileSync)也会使用 throw 报告错误。

异步异常

callback

错误优先的回调函数:该函数会接受一个 Error 对象传入作为第一个参数。 如果第一个参数不是 null 而是一个 Error 实例,则说明发生了错误,应该进行处理。

const fs = require('fs');
fs.readFile('一个不存在的文件', (err, data) => {
  if (err) {
    console.error('读取文件出错!', err);
    return;
  }
  // 否则处理数据
});
event

error 事件机制:当一个异步方法被一个 EventEmitter 对象调用时,错误会被分发到对象的 ‘error’ 事件上。

const net = require('net');
const connection = net.connect('localhost');

// 添加一个 'error' 事件句柄到一个流:
connection.on('error', (err) => {
  // 如果连接被服务器重置,或无法连接,或发生任何错误,则错误会被发送到这里。 
  console.error(err);
});

connection.pipe(process.stdout);
Promise

Promise.prototype.catch()

const promise = new Promise(function(resolve, reject) {
  throw new Error('promise error');
});
promise.catch(function(error) {
  console.error(error); // Error: promise error
});
Async/Await
  1. try…catch:async/await让异步操作同步执行,可以使用跟同步异常捕获的方式捕获处理async函数的异常。
async function f() {
  try {
    await Promise.reject('出错了');
  } catch(e) {
    console.error(e); // 出错了
  }
  return await Promise.resolve('hello world');
}

f().then(v => console.log(v)) // hello world
  1. Promise.prototype.catch():Async/Await 本质也是基于Promise的,同样可以使用Promise.prototype.catch()捕获处理异常。
async function f() {
  await Promise.reject('出错了')
    .catch(e => console.error(e)); // 出错了

  return await Promise.resolve('hello world');
}

f().then(v => console.log(v)) // hello world

uncaughtException异常

没有人可以确保代码没有异常,同样也没有人可以确保代码里的异常能百分百被捕获处理。当未捕获的 JavaScript 异常一直冒泡回到事件循环时,则会触发 ‘uncaughtException’ 事件。

process.on('uncaughtException', (e)=>{  
  console.error(e); // Error: uncaughtException
  // do something: 释放相关资源(例如文件描述符、句柄等)
  process.exit(1); // 手动退出进程
});

throw new Error('uncaughtException')

注意: 正确使用 uncaughtException
uncaughtException 是用于异常处理的粗略机制,仅用作最后的补救手段。 未处理的异常本质上意味着应用程序处于某种未知状态。在 uncaughtException 之后继续执行操作是不安全的,因为异常不可预料的发生后,程序直接从对应执行栈中断而到process捕获的异常事件下,导致了v8引擎的垃圾回收功能不能按照正常流程工作,然后出现内存泄漏问题。uncaughtException 的正确用法是在关闭进程之前对分配的资源(例如文件描述符、句柄等)执行同步清理并手动退出进程,使用进程管理工具(如pm2,docker等)监视故障重新启动。

参考资料:
Node.js官方手册 - Error
Node.js官方手册 - Process
ES6 入门教程- ECMAScript 6入门 - 阮一峰

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值