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

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

问题描述

我几天前才开始尝试 node.js.我已经意识到,每当我的程序中出现未处理的异常时,节点就会终止.这与我接触过的普通服务器容器不同,其中只有 Worker Thread 在发生未处理的异常时死亡,并且容器仍然能够接收请求.这引发了几个问题:

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:

  • process.on('uncaughtException') 是唯一有效的防范方法吗?
  • process.on('uncaughtException') 是否也会在异步进程执行期间捕获未处理的异常?
  • 是否有一个已经构建好的模块(例如发送电子邮件或写入文件),我可以在未捕获异常的情况下利用它?
  • 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?

我希望能向我展示在 node.js 中处理未捕获异常的常见最佳实践的任何指针/文章

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

推荐答案

更新:Joyent 现在拥有 他们自己的指南.以下信息更像是一个摘要:

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

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

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)
}

  • 对于基于回调(即异步)的代码,回调的第一个参数是 err,如果发生错误 err 是错误,如果不会发生错误,然后 errnull.err 参数后面的任何其他参数:

  • 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)
        }
    })
    

  • 对于 eventful 代码,错误可能发生在任何地方,而不是抛出错误,改为触发 error 事件:

  • 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)
    

  • 尽管有时,仍然可能有代码在某处抛出错误,如果我们不安全地捕获它,这可能导致未捕获的异常和我们的应用程序的潜在崩溃.根据我们的代码架构,我们可以使用以下方法之一来捕获它:

    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:

    • 当我们知道错误发生在哪里时,我们可以将该部分包装在 node.js 中域

    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
    })
    

  • 如果我们知道错误发生的地方是同步代码,并且由于某种原因不能使用域(可能是旧版本的节点),我们可以使用 try catch 语句:

  • 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)
    }
    

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

    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
    }
    

    如果您确实希望将 try..catch 与异步代码结合使用,则在运行 Node 7.4 或更高版本时,您可以原生使用 async/await 来编写您的异步函数.

    If you do want to work with try..catch in conjunction with asynchronous code, when running Node 7.4 or higher you can use async/await natively to write your asynchronous functions.

    使用 try...catch 需要注意的另一件事是将完成回调包含在 try 语句中的风险,如下所示:

    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
    }
    

    随着您的代码变得更加复杂,这个问题很容易做到.因此,最好使用域或返回错误以避免 (1) 异步代码中未捕获的异常 (2) try catch 捕获您不希望的执行.在允许使用适当线程而不是 JavaScript 的异步事件机样式的语言中,这不是什么问题.

    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.

    最后,如果未捕获的错误发生在未包含在域或 try catch 语句中的地方,我们可以使用 uncaughtException 侦听器(但是这样做会使应用程序处于未知状态):

    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天全站免登陆