当前位置: 首页 > 面试题库 >

Node.js最佳实践异常处理

龚沛
2023-03-14
问题内容

几天前我才开始尝试使用node.js。我意识到只要程序中有未处理的异常,Node就会终止。这与我所见过的普通服务器容器不同,在普通服务器容器中,当发生未处理的异常时,只有工作线程死亡,并且容器仍然能够接收请求。这引起了一些问题:

  • process.on('uncaughtException')唯一有效的预防方法吗?
  • process.on('uncaughtException')在执行异步过程期间也会捕获未处理的异常吗?
  • 是否存在已经构建的模块(例如发送电子邮件或写入文件),在未捕获的异常的情况下可以利用该模块?

我将不胜感激任何向我展示在node.js中处理未捕获异常的常见最佳实践的指针/文章


问题答案:

更新:Joyent现在有自己的指南。以下信息更多是摘要:

安全地“抛出”错误

理想情况下,我们希望尽可能避免未捕获的错误,因此,除了从字面上抛出错误外,我们还可以根据我们的代码体系结构使用以下方法之一安全地“抛出”错误:

  • 对于同步代码,如果发生错误,请返回错误:
        // 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则为错误,如果未发生错误err则为null。其他任何参数都遵循以下err参数:
        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)
        }
    })
  • 对于事件代码,错误可能发生在任何地方,而不是引发错误,请触发error事件:
        // 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)

安全地“捕捉”错误

但是有时,仍然有一些代码会在某个地方引发错误,如果我们不安全地捕获它,可能会导致未捕获的异常并可能导致应用程序崩溃。根据我们的代码体系结构,我们可以使用以下方法之一来捕获它:

  • 当我们知道错误发生在哪里时,可以将该部分包装在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语句:
        // 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在异步代码中使用,因为不会捕获异步引发的错误:

        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本机来编写异步函数。

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

        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)尝试捕获不需要的执行。在允许适当的线程而不是JavaScript的异步事件机器风格的语言中,这不是问题。

  • 最后,在未包裹域或try catch语句的地方发生未捕获的错误的情况下,我们可以使用uncaughtException侦听器使应用程序不崩溃(但是这样做会使应用程序处于未知状态)):
        // 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


 类似资料:
  • 问题内容: 如果我的应用程序崩溃了,它会挂起几秒钟,然后Android告诉我该应用程序崩溃了,需要关闭。所以我当时想用通用的方式捕获应用程序中的所有异常: 并做一个新的解释,说明应用程序立即崩溃(并且还使用户有机会发送包含错误详细信息的邮件),而不是由于Android而造成了延迟。是否有更好的方法来实现这一目标? 更新: 我使用的是启用了ART的Nexus 5,但我没有注意到我以前遇到的崩溃(我最

  • 并创建一个新的,解释应用程序立即崩溃(并给用户发送包含错误详细信息的邮件的机会),而不是由于Android造成的延迟。有没有更好的方法来实现这一点,或者这是不鼓励的? 更新:我使用的Nexus 5启用了ART功能,我没有注意到应用程序崩溃时的延迟(我最初说的“挂起”)。我想既然现在一切都是本机代码,崩溃就会立即发生,同时得到所有的崩溃信息。也许Nexus5只是速度很快:)不管怎样,这在未来的And

  • 9 Node.js 最佳实践 9.1 配置文件 一般代码的运行的环境起码应该包括本地开发环境和线上运行环境,那么问题来了,你开发环境用的配置信息可是跟线上环境不一样的。那么已经存储这个配置信息呢?在代码中写死肯定是最low的方式。更通用的方式是使用配置文件,可是你一旦将这个配置文件就面临一个问题,你这个配置文件一旦提交到了 git 之后,你的同事 pull 代码之后,就有可能就他本地配置文件覆盖掉

  • 本文向大家介绍详解Spring MVC/Boot 统一异常处理最佳实践,包括了详解Spring MVC/Boot 统一异常处理最佳实践的使用技巧和注意事项,需要的朋友参考一下 前言 在 Web 开发中, 我们经常会需要处理各种异常, 这是一件棘手的事情, 对于很多人来说, 可能对异常处理有以下几个问题: 什么时候需要捕获(try-catch)异常, 什么时候需要抛出(throws)异常到上层. 在

  • 问题内容: 我有一个普通的Node.js脚本,该脚本通过API从Wikipedia中提取数据并将其存储在SQLite数据库中。我正在使用此node- sqlite3 模块。 在某些情况下,我要提取多达60万篇文章中的数据,并在数据库中连续存储有关每篇文章的一些元数据。从API中以500为一组检索文章。 检索带有500条文章中的数据的JSON对象的请求将对象传递给此回调: 这些模块默认情况下并行运行

  • 问题内容: 我最近写了我的第一个Android应用程序,大约有8,000-10,000行代码。一直阻碍我使用常规设计模式的一件事是android对异步调用(打开对话框,活动等)的大量使用。因此,我的代码很快就开始看起来像“意大利面”,而我最终开始不喜欢某些类。 是否有适用于任何人都会推荐的系统的特定设计模式或编程方法?对于编写可管理的异步代码有什么建议吗? 问题答案: 使用全局变量 如果您不想用简