Node.js 异常处理最佳实践

2023-11-29

几天前我刚刚开始尝试 Node.js。我意识到每当我的程序中出现未处理的异常时,节点就会终止。这与我接触过的普通服务器容器不同,在普通服务器容器中,当发生未处理的异常时,只有工作线程会终止,并且容器仍然能够接收请求。这提出了几个问题:

  • Is process.on('uncaughtException')唯一有效的防范方法是什么?
  • Will 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 is 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)
          }
      })
    
  • For eventful代码,其中错误可能发生在任何地方,而不是抛出错误,而是触发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原生地编写异步函数。

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.
  • 最后,如果未捕获的错误发生在未包含在域或 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
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Node.js 异常处理最佳实践 的相关文章

随机推荐

  • 带有 VSTS 的 SonarCloud 出现错误 Duplicate ProjectGuid: "00000000-0000-0000-0000-000000000000"

    我们将 SonarCloud 添加到大型解决方案的构建管道中 我们的解决方案中仅分析了一个项目 但我们看到了此警告 警告 以下项目没有有效的 ProjectGuid 并且不是使用有效的解决方案 sln 构建的 因此将从分析中跳过 D a 1
  • 如何在控制台应用程序中使文本居中? [复制]

    这个问题在这里已经有答案了 我正在创建一个控制台应用程序 我需要将文本居中 有没有一种简单的方法可以做到这一点 或者我是否必须在文本之前放置空格直到它居中 感谢您的帮助 例如 使用 作为控制台的中心 你好 世界 string s Hello
  • R - Rselenium - 使用 = 'id' 导航下拉菜单/列表/框

    如何通过 using id 导航动态下拉列表 例如 remDr findElement using id value main ddYear 我可以找到并单击使用findElement 单击后 如果我知道我的目标选择有多少个向下箭头 我可以
  • 将sql字符串拆分为单词

    我想将字符串拆分成如下所示的单词 所有字符串的输出应该相同 INPUT 1 This is a string 2 This is a string 3 This is a string 4 This is a string OUTPUT 这
  • 不使用 MFMessageComposeViewController 发送消息

    我喜欢制作自己的 iMessages 消息应用程序 该应用程序基本上已准备就绪 但我不知道如何在不显示 MFMessageComposeViewController 的情况下发送 iMessage 我知道有办法 他们在 ByteSMS 和所
  • 缩小 C++0x 中的转换范围。是只有我这么认为,还是这听起来像是一个重大改变?

    C 0x 将使以下代码和类似代码格式错误 因为它需要所谓的缩小转换范围 of a double to a int int a 1 0 我想知道这种初始化在现实世界的代码中是否经常使用 此更改会破坏多少代码 如果您的代码受到影响 需要付出很大
  • 使用两个 Android 应用程序的内容提供程序示例

    我想要insert or delete我当前的 Android 应用程序中另一个 Android 应用程序数据库中的值 我搜索了很多 大家都说用 content provider 它不与两个应用程序一起使用 所有两个应用程序都在一个应用程序
  • android:largescreens: = "true" 的属性值语法无效

    我正在开发一个 android 应用程序 minSdkVersion 为 11 targetSdkVersion 为 17 我正在为多种屏幕尺寸设计这个应用程序 所以我将对所有屏幕的支持放在清单文件中 我希望这个应用程序支持所有密度 我的
  • scikit-learn 中的 class_weight 参数如何工作?

    我很难理解如何class weightscikit learn 的逻辑回归中的参数运行 情况 我想使用逻辑回归对非常不平衡的数据集进行二元分类 这些类别被标记为 0 阴性 和 1 阳性 观察到的数据比例约为 19 1 大多数样本具有阴性结果
  • 使用 javascript 提取支持的 HTML 或 X11 颜色名称及其 RGB 值的列表

    有一些地方可以获取列表HTML or X11 颜色名称及其 RGB 等效项 例如我们可以发现 Aquamarine 是 70DB93 想必浏览器知道这些映射 有没有办法使用 javascript 询问浏览器并获取它支持的颜色名称列表 以及浏
  • SQL Server 连接超时

    我可以通过修改连接字符串来增加超时时间吗web config 是的 您可以附加 Connection Timeout 30给你的连接字符串并指定您想要的值 中设置的超时值Connection Timeout财产是一个以秒表示的时间 如果未设
  • Android ListView y 位置

    看起来 ListView 不像 ScrollView 那样公开它的 y 位置 换句话说 我需要记住 ListView 滚动到的确切位置 并在返回活动时设置它 只是为了澄清 我不需要所选的项目 这非常简单 我需要恢复 ListView 上精确
  • 而不是触发器来更新具有多个表的视图

    我试图找到一个示例 说明如何使用替代触发器更新多个表上的视图 也就是说 我想要更新该视图从中选择的多个表 我找不到任何例子 如果有人能告诉我如何做到这一点那就太好了 假设您在这里使用的是 SQLServer过于简单化 example CRE
  • 在回发时保留单选/复选框值?

    ASP 对象有一些我无法理解的东西 我在更新面板中有一个按钮 在同一页面上 我有一个复选框 一个单选按钮和一个文本框 在更新面板之外 当我单击按钮时 我可以访问所有这三个对象 文本框能够保留其文本值 但是当我检查选中状态时 单选 复选框总是
  • Pytorch 问题:当 num_workers > 0 时,我的 jupyter 卡住了

    这是我在 PyTorch 中的代码片段 当我使用 num workers gt 0 时 我的 jupiter 笔记本卡住了 我在这个问题上花了很多时间却没有任何答案 我没有 GPU 仅使用 CPU class IndexedDataset
  • 猫鼬发现返回奇怪的对象

    我当前的问题是 db collection find mongoose 命令 我对 mongoose mongodb 比较陌生 但我已经掌握了它的概念 这是我一直试图运行的测试代码 mongoose connect url function
  • 如何在 Ironpython 中使用 –X:Frames?

    Visual Studio 2010 Ironpython for net4 我想在ironpython中使用numpy 他们说我必须使用框架支持 因此 我应该在命令行上使用 X Frames 或 X FullFrames 运行 ipy 但
  • 在错误消息中显示行号

    在我使用过的大多数 MATLAB 实例中 每当我的代码中出现错误时 命令窗口中的错误消息都会显示行号 但是在我当前使用的计算机上 它仅显示以下内容 Subscripted assignment dimension mismatch 有没有办
  • C 中 bool 数据类型的 scanf 格式说明符

    我在 C std99 中使用 bool 数据类型 其定义在
  • Node.js 异常处理最佳实践

    几天前我刚刚开始尝试 Node js 我意识到每当我的程序中出现未处理的异常时 节点就会终止 这与我接触过的普通服务器容器不同 在普通服务器容器中 当发生未处理的异常时 只有工作线程会终止 并且容器仍然能够接收请求 这提出了几个问题 Is