关于node.js:nodejs中的异常错误处理

38次阅读

共计 3261 个字符,预计需要花费 9 分钟才能阅读完成。

异样解决是程序运行中必须要关注的中央,当异样呈现后,应该第一工夫关注到,并且疾速解决。大部分程序员们都不敢保障本人的代码百分比正确,所以应该在写代码时就要对异样提前做预防解决,尽量保障在异样呈现时,给用户一个敌对的提醒,不至于服务挂起导致申请超时,并且能将异样信息做记录上报,不便前期排查解决。

一. 同步代码的异样捕捉解决

  1. 同步代码中的异样应用 try{}catch 构造即可捕捉解决。

    
    try {throw new Error('错误信息');
    } catch (e) {console.error(e.message);
    }

    能够失常捕捉到。

二. 异步代码的错误处理

  1. try/catch 接口

异步代码下应用 try{}catch 构造捕捉解决成果如何呢?

try {setTimeout(()=>{throw new Error('错误信息');
  })
} catch (e) {console.error('error is:', e.message);
}

然而却没有捕捉到异步谬误。

  1. process 的 uncaughtException 事件

那异步谬误该怎么解决呢?首先换个思维,因为异样并不是当时筹备好的,不能管制其到底在哪儿产生,所以站更高的角度,如监听利用过程的谬误异样,从而捕捉不能意料的谬误异样,保障利用不至于奔溃调。

process.on('uncaughtException', (e)=>{console.error('process error is:', e.message);
});

如上代码从 process 上监听 uncaughtException 事件,能够捕捉到整个过程蕴含异步中的错误信息,从而保障利用没有奔溃。

然而新的问题随之而来,因为异样不可意料的产生后,当异样呈现时,间接从对应执行栈中断,而到 process 捕捉的异样事件下,导致了 v8 引擎的垃圾回收性能不能依照失常流程工作,而后开始呈现内存透露问题。

绝对于异样来说,内存透露也是一个不能漠视的重大问题,而 process.on(‘uncaughtException’)的做法,很难去保障不造成内存的透露。所以当捕捉到异样时,显式的手动杀掉过程,并开始重启 node 过程,即保障开释内存,又保障了保障服务后续失常可用。

process.on('uncaughtException', (e)=>{console.error('process error is:', e.message);
  process.exit(1);
  restartServer(); // 重启服务});

然而下面的做法有一点间接,大家未免存纳闷,如果单过程单实例的部署下,杀掉过程在重启这一段时间内服务不能失常可用怎么办?这显然是不合理的。

  1. 应用 domain 模块
    domain 模块,把解决多个不同的 IO 的操作作为一个组。注册事件和回调到 domain,当产生一个谬误事件或抛出一个谬误时,domain 对象会被告诉,不会失落上下文环境,也不导致程序谬误立刻退出,与 process.on(‘uncaughtException’) 不同。

Domain 模块可分为隐式绑定和显式绑定:
隐式绑定: 把在 domain 上下文中定义的变量,主动绑定到 domain 对象
显式绑定: 把不是在 domain 上下文中定义的变量,以代码的形式绑定到 domain 对象


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

d.on('error', (err) => {console.log('err', err.message);
  console.log(needSend.message);
});

const needSend = {message: '须要传递给错误处理的一些信息'};
d.add(needSend);

function excute() {
  try {setTimeout(()=>{throw new Error('错误信息');
    });
  } catch (e) {console.error('error is:', e.message);
  }
};

d.run(excute);

domin 显著的长处,能把出问题时的一些信息传递给谬误处理函数,能够做一些打点上报等解决工作,最起码保障重启后的服务,程序猿们晓得产生了什么,有线索可查,也能够抉择传递上下文进去,做一些后续解决。比方当服务出错的时候,能够把用户申请栈信息传给上游,返回告知用户服务异样,而不是用户始终等到申请主动超时。

...
d.add(res);
...
d.on('error', (err) => {console.log('err', err.message);
  res.end('服务器产生异样,请稍后再试!');
});

然而它和 process.on(‘uncaughtException’)的做法一样,很难去保障不造成内存的透露。

另外在官网文档上,domain 模块解决废除状态,然而当初也没有其余计划能够齐全代替 domain 模块,然而我当初 node10 的版本仍旧能够用,临时应该不必放心 domain 模块被废除的问题。

三. 多过程模式加异样捕捉后重启
下面的形式没有完满解决问题,思考一下如何可能让异样产生后不奔溃,捕捉异样后不造成内存透露,而且重启开释缓存不造成服务不可用呢?

一种比拟好的计划是,以多过程(cluster)的模式去部署利用,当某一个过程被异样捕捉后,能够做一下打点上报后,开始重启开释内存,此时其余申请被承受后,其余过程仍旧能够对外提供服务,当然前提是你的利用不能异样多的数都数不清。

上面是将 cluster 和 domain 联合起来应用,以多过程的形式保障服务可用,同时能够将错误信息传递上来进行上报,并且保留谬误呈现的上下文环境,给用户返回申请,不让用户申请超时,而后在手动杀死异样过程,而后重启。

const cluster = require('cluster');
const os = require('os');
const http = require('http');
const domain = require('domain');

const d = domain.create();

if (cluster.isMaster) {const cpuNum = os.cpus().length;
  for (let i = 0; i < cpuNum; ++i) {cluster.fork()
  };
  // fork work log
  cluster.on('fork', worker=>{console.info(`${new Date()} worker${worker.process.pid}过程启动胜利 `);
  });
  // 监听异样退出过程,并从新 fork
  cluster.on('exit',(worker,code,signal)=>{console.info(`${new Date()} worker${worker.process.pid}过程启动异样退出 `);
    cluster.fork();})
} else {http.createServer((req, res)=>{d.add(res);
    d.on('error', (err) => {console.log('记录的 err 信息', err.message);
      console.log('出错的 work id:', process.pid);
      // uploadError(err)  // 上报错误信息至监控
      res.end('服务器异样, 请稍后再试');
      // 将异样子过程杀死
      cluster.worker.kill(process.pid);
    });
    d.run(handle.bind(null, req, res));
  }).listen(8080);
}

function handle(req, res) {if (process.pid % 2 === 0) {throw new Error(` 出错了 `);
  }
  res.end(`response by worker: ${process.pid}`);
};

有趣味的同学强烈建议把代码拷贝到本地后本人调试察看。

关键词: 前端培训

正文完
 0