Node.js最佳实践异常处理 [英] Node.js Best Practice Exception Handling

查看:100
本文介绍了Node.js最佳实践异常处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始尝试在几天前的node.js。我已经意识到,当我的程序中有一个未处理的异常时,Node被终止。这与我已经暴露于正常的服务器容器不同,只有当工作线程在未处理的异常发生时才会死机,并且容器仍然能够接收到请求。这提出了一些问题:




  • process.on('uncaughtException')唯一有效的方法来防范它?

  • 在执行异步进程期间, process.on('uncaughtException')会捕获未处理的异常?

  • 是否有一个已经建立的模块(如发送电子邮件或写入文件),我可以在未捕获的例外情况下利用这个模块?



我会感谢任何指针/文章,将显示在node.js中处理未捕获异常的常见最佳做法

解决方案

更新:Joyent现在已经自己的指南此答案中提及。以下信息是更多摘要:



安全地抛出错误



理想情况下,我们希望尽可能避免未捕获的错误,因此,根据我们的代码架构,我们可以使用以下方法之一安全地抛出错误,而不是直接抛出错误:




  • 对于同步代码,如果发生错误,请返回错误:

      //将分隔符定义为一个syncrhonous函数
    var divideSync = function(x,y){
    //如果错误条件?
    if(y === 0){
    //通过返回来安全地抛出错误
    返回新错误(不能除以零)
    }
    else {
    //没有错误发生,继续在
    返回x / y
    }
    }

    // Divide 4/2
    var result = divideSync(4,2)
    //发生错误?
    if(result instanceof Error){
    //安全处理错误
    console.log('4/2 = err',result)
    }
    else {
    //没有错误发生,继续在
    console.log('4/2 ='+ result)
    }

    // Divide 4/0
    result = divideSync(4,0)
    //发生错误?
    if(result instanceof Error){
    //安全处理错误
    console.log('4/0 = err',result)
    }
    else {
    //没有错误发生,继续在
    console.log('4/0 ='+ result)
    }


  • 对于基于回调(即异步)的代码,回调的第一个参数是 err ,if发生错误 err 是错误,如果错误不会发生,那么 err 。任何其他参数都遵循 err 参数:

      var divide = function x,y,next){
    //如果错误条件?
    if(y === 0){
    //通过调用完成回调
    //安全地抛出错误,第一个参数是错误
    next(new错误(不能除以零)
    }
    else {
    //没有错误发生,继续
    next(null,x / y)
    }
    }

    divide(4,2,function(err,result){
    //发生错误
    if(err){
    //安全地处理错误
    console.log('4/2 = err',err)
    }
    else {
    //没有错误发生,继续在
    console.log('4/2 ='+ result)
    }
    })

    divide(4,0,function(err,result){
    //发生错误
    if(err){
    //安全地处理错误
    console.log('4/0 = err',err)

    else {
    //没有发生错误,继续在
    console.log('4/0 ='+ result)
    }
    })


  • 对于繁忙的代码,错误可能发生在任何地方,而不是投掷错误,请 错误事件

      //确定我们的分隔符事件发射器
    var events = require('events')
    var Divider = function(){
    events.EventEmitter.call(this)
    }
    require('util')。inherits(Divider,events.EventEmitter)

    //添加除法函数
    Divider.prototype.divide = function(x,y){
    //如果错误条件?
    if(y === 0){
    //通过发送安全地抛出错误
    var err = new错误(不能除以零)
    this.emit('error',err)
    }
    else {
    //没有错误发生,继续在
    this.emit('divide',x,y, x / y)
    }

    //链
    返回此;
    }

    //创建我们的分隔符并侦听错误
    var divider = new Divider()
    divider.on('error',function(err){
    //安全地处理错误
    console.log(err)
    })
    divider.on('divide',function(x,y,result){
    console.log(x +'/'+ y +'='+ result)
    })

    //除以
    divider.divide(4,2).divide(4 ,0)




安全地捕捉错误



有时候,如果我们不能安全捕获,有时候仍然可能会有代码在某处导致一个未捕获的异常以及潜在的应用程序崩溃。根据我们的代码架构,我们可以使用以下方法来捕获它:




  • 当我们知道发生错误的地方我们可以将该部分包含在 node.js域

      var d = require('domain')。create()
    d.on('error',function(err){
    / /安全处理错误
    console.log(err)
    })

    //捕获此异步或同步代码块中未捕获的错误
    d.run function(){
    //我们要捕获的异步或同步代码抛出错误
    var err = new Error('example')
    throw err
    })


  • 如果我们知道发生错误的位置是同步代码,无论什么原因使用域(可能是旧版本的节点),我们可以使用try catch语句:

      //捕获未知的错误同步代码块
    // try catch语句只适用于同步代码
    try {
    //我们要捕获的同步代码抛出错误
    var err = new Error('例子')
    throw err
    } catch(err){
    //安全地处理错误
    console.log(err)
    }

    但是,请注意不要在异步中使用 try ... catch 代码,作为异步抛出的错误不会被捕获:

      try {
    setTimeout(function(){
    var err = new Error('example')
    throw err
    },1000)
    }
    catch(err){
    //示例错误赢得'被抓到这里...崩溃我们的应用程序
    //因此需要域
    }

    另外需要注意的是, try ... catch 是将 try 语句如下:

      var divide = function(x,y,next){
    //如果错误条件?
    if(y === 0){
    //通过调用完成回调
    //安全地抛出错误,第一个参数是错误
    next(new错误(不能除以零)
    }
    else {
    //没有错误发生,继续
    next(null,x / y)
    }
    }

    var continueElsewhere = function(err,result){
    throw new Error('others have failed')
    }

    try {
    divide(4,2,continueElsewhere)
    // ^执行分割,执行
    // continueElsewhere将在try语句内
    }
    catch(err){
    console.log(err.stack)
    // ^将输出意外结果:其他地方失败
    }

    这个getcha很容易做,因为你的代码变得更加复杂。因此,最好是使用域或返回错误以避免(1)异步代码中未捕获的异常(2)try catch捕获您不希望执行的执行。在允许适当线程代替JavaScript的异步事件机器风格的语言中,这不是一个问题。


  • 最后,在未捕获的错误的情况下发生在没有包装在域中的地方或try catch语句中,我们可以使用 uncaughtException 监听器使我们的应用程序不会崩溃(但是这样做可以使未知状态中的应用程序):



    //捕获未包含在域中的未捕获的错误或尝试捕获语句
    //不要在模块中使用此错误,而仅在应用程序中使用我们可以有多个这些绑定
    process.on('uncaughtException',function(err){
    //安全地处理错误
    console.log(err)
    })

    //发出另外未捕获的错误的异步或同步代码
    var err = new Error(例如)
    掷ERR



I just started trying out node.js a few days ago. I've realized that the Node is terminated whenever I have an unhandled exception in my program. This is different than the normal server container that I have been exposed to where only the Worker Thread dies when unhandled exceptions occur and the container would still be able to receive the request. This raises a few questions:

  • Is process.on('uncaughtException') the only effective way to guard against it?
  • Will process.on('uncaughtException') catch the unhandled exception during execution of asynchronous processes as well?
  • Is there a module that is already built (such as sending email or writing to a file) that I could leverage in the case of uncaught exceptions?

I would appreciate any pointer/article that would show me the common best practices for handling uncaught exceptions in node.js

解决方案

Update: Joyent now has their own guide mentioned in this answer. The following information is more of a summary:

Safely "throwing" errors

Ideally we'd like to avoid uncaught errors as much as possible, as such, instead of literally throwing the error, we can instead safely "throw" the error using one of the following methods depending on our code architecture:

  • For synchronous code, if an error happens, return the error:

    // Define divider as a syncrhonous function
    var divideSync = function(x,y) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by returning it
            return new Error("Can't divide by zero")
        }
        else {
            // no error occured, continue on
            return x/y
        }
    }
    
    // Divide 4/2
    var result = divideSync(4,2)
    // did an error occur?
    if ( result instanceof Error ) {
        // handle the error safely
        console.log('4/2=err', result)
    }
    else {
        // no error occured, continue on
        console.log('4/2='+result)
    }
    
    // Divide 4/0
    result = divideSync(4,0)
    // did an error occur?
    if ( result instanceof Error ) {
        // handle the error safely
        console.log('4/0=err', result)
    }
    else {
        // no error occured, continue on
        console.log('4/0='+result)
    }
    

  • For callback-based (ie. asynchronous) code, the first argument of the callback is err, if an error happens err is the error, if an error doesn't happen then err is null. Any other arguments follow the err argument:

    var divide = function(x,y,next) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by calling the completion callback
            // with the first argument being the error
            next(new Error("Can't divide by zero"))
        }
        else {
            // no error occured, continue on
            next(null, x/y)
        }
    }
    
    divide(4,2,function(err,result){
        // did an error occur?
        if ( err ) {
            // handle the error safely
            console.log('4/2=err', err)
        }
        else {
            // no error occured, continue on
            console.log('4/2='+result)
        }
    })
    
    divide(4,0,function(err,result){
        // did an error occur?
        if ( err ) {
            // handle the error safely
            console.log('4/0=err', err)
        }
        else {
            // no error occured, continue on
            console.log('4/0='+result)
        }
    })
    

  • For eventful code, where the error may happen anywhere, instead of throwing the error, fire the error event instead:

    // Definite our Divider Event Emitter
    var events = require('events')
    var Divider = function(){
        events.EventEmitter.call(this)
    }
    require('util').inherits(Divider, events.EventEmitter)
    
    // Add the divide function
    Divider.prototype.divide = function(x,y){
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by emitting it
            var err = new Error("Can't divide by zero")
            this.emit('error', err)
        }
        else {
            // no error occured, continue on
            this.emit('divided', x, y, x/y)
        }
    
        // Chain
        return this;
    }
    
    // Create our divider and listen for errors
    var divider = new Divider()
    divider.on('error', function(err){
        // handle the error safely
        console.log(err)
    })
    divider.on('divided', function(x,y,result){
        console.log(x+'/'+y+'='+result)
    })
    
    // Divide
    divider.divide(4,2).divide(4,0)
    

Safely "catching" errors

Sometimes though, there may still be code that throws an error somewhere which can lead to an uncaught exception and a potential crash of our application if we don't catch it safely. Depending on our code architecture we can use one of the following methods to catch it:

  • When we know where the error is occurring, we can wrap that section in a node.js domain

    var d = require('domain').create()
    d.on('error', function(err){
        // handle the error safely
        console.log(err)
    })
    
    // catch the uncaught errors in this asynchronous or synchronous code block
    d.run(function(){
        // the asynchronous or synchronous code that we want to catch thrown errors on
        var err = new Error('example')
        throw err
    })
    

  • If we know where the error is occurring is synchronous code, and for whatever reason can't use domains (perhaps old version of node), we can use the try catch statement:

    // catch the uncaught errors in this synchronous code block
    // try catch statements only work on synchronous code
    try {
        // the synchronous code that we want to catch thrown errors on
        var err = new Error('example')
        throw err
    } catch (err) {
        // handle the error safely
        console.log(err)
    }
    

    However, be careful not to use try...catch in asynchronous code, as an asynchronously thrown error will not be caught:

    try {
        setTimeout(function(){
            var err = new Error('example')
            throw err
        }, 1000)
    }
    catch (err) {
        // Example error won't be caught here... crashing our app
        // hence the need for domains
    }
    

    Another thing to be careful about with try...catch is the risk of wrapping your completion callback inside the try statement like so:

    var divide = function(x,y,next) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by calling the completion callback
            // with the first argument being the error
            next(new Error("Can't divide by zero"))
        }
        else {
            // no error occured, continue on
            next(null, x/y)
        }
    }
    
    var continueElsewhere = function(err, result){
            throw new Error('elsewhere has failed')
    }
    
    try {
            divide(4, 2, continueElsewhere)
            // ^ the execution of divide, and the execution of 
            //   continueElsewhere will be inside the try statement
    }
    catch (err) {
            console.log(err.stack)
            // ^ will output the "unexpected" result of: elsewhere has failed
    }
    

    This gotcha is very easy to do as your code becomes more complex. As such, it is best to either use domains or to return errors to avoid (1) uncaught exceptions in asynchronous code (2) the try catch catching execution that you don't want it to. In languages that allow for proper threading instead of JavaScript's asynchronous event-machine style, this is less of an issue.

  • Finally, in the case where an uncaught error happens in a place that wasn't wrapped in a domain or a try catch statement, we can make our application not crash by using the uncaughtException listener (however doing so can put the application in an unknown state):

    // catch the uncaught errors that weren't wrapped in a domain or try catch statement
    // do not use this in modules, but only in applications, as otherwise we could have multiple of these bound
    process.on('uncaughtException', function(err) {
        // handle the error safely
        console.log(err)
    })
    
    // the asynchronous or synchronous code that emits the otherwise uncaught error
    var err = new Error('example')
    throw err
    

这篇关于Node.js最佳实践异常处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆