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

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

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


当前回答

我最近在http://snmaynard.com/2012/12/21/node-error-handling/.0.8版本中node的一个新功能是域,它允许您将所有形式的错误处理合并到一个更简单的管理表单中。您可以在我的文章中阅读它们。

您还可以使用Bugsnag之类的工具来跟踪未捕获的异常,并通过电子邮件、聊天室或创建未捕获异常的罚单(我是Bugsnag的联合创始人)获得通知。

其他回答

nodejs域是处理nodejs中错误的最新方法。域可以捕获错误/其他事件以及传统抛出的对象。域还提供了处理回调的功能,其中错误通过intercept方法作为第一个参数传递。

与正常的try/catch风格的错误处理一样,通常最好在错误发生时抛出错误,并将您希望隔离错误的区域排除在外,以免影响代码的其余部分。“屏蔽”这些区域的方法是调用domain.run,将一个函数作为隔离代码块。

在同步代码中,以上内容就足够了——当发生错误时,要么让它被抛出,要么抓住它并在那里处理,还原需要还原的任何数据。

try {  
  //something
} catch(e) {
  // handle data reversion
  // probably log too
}

当错误发生在异步回调中时,您要么需要能够完全处理数据的回滚(共享状态、数据库等外部数据)。或者,您必须设置一些东西来指示发生了异常——如果您关心该标志,则必须等待回调完成。

var err = null;
var d = require('domain').create();
d.on('error', function(e) {
  err = e;
  // any additional error handling
}
d.run(function() { Fiber(function() {
  // do stuff
  var future = somethingAsynchronous();
  // more stuff

  future.wait(); // here we care about the error
  if(err != null) {
    // handle data reversion
    // probably log too
  }

})});

上面的一些代码很难看,但您可以为自己创建模式以使其更漂亮,例如:

var specialDomain = specialDomain(function() {
  // do stuff
  var future = somethingAsynchronous();
  // more stuff

  future.wait(); // here we care about the error
  if(specialDomain.error()) {
    // handle data reversion
    // probably log too
  } 
}, function() { // "catch"
  // any additional error handling
});

更新(2013-09):

上面,我使用了一个未来,它暗示了纤维语义,允许您在线等待未来。这实际上允许你在所有事情上使用传统的try-catch块,我认为这是最好的方法。然而,你不能总是这样做(即在浏览器中)。。。

还有一些未来不需要纤维语义(然后使用普通的浏览器JavaScript)。这些可以被称为期货、承诺或延期(我将从这里开始提及期货)。普通的旧JavaScript期货库允许在期货之间传播错误。只有其中的一些库允许正确处理任何抛出的未来,所以要小心。

例如:

returnsAFuture().then(function() {
  console.log('1')
  return doSomething() // also returns a future

}).then(function() {
  console.log('2')
  throw Error("oops an error was thrown")

}).then(function() {
  console.log('3')

}).catch(function(exception) {
  console.log('handler')
  // handle the exception
}).done()

这模拟了正常的try-catch,即使片段是异步的。它将打印:

1
2
handler

请注意,它不打印“3”,因为引发了中断该流的异常。

看看蓝鸟的承诺:

https://github.com/petkaantonov/bluebird

注意,除了这些库之外,我还没有找到其他许多库可以正确处理抛出的异常。jQuery的延迟,例如,不要-“fail”处理程序永远不会让“then”处理程序抛出异常,在我看来,这是一个交易破坏者。

前段时间读了这篇文章后,我想知道在api/函数级别上使用域进行异常处理是否安全。我想用它们来简化我编写的每个异步函数中的异常处理代码。我担心的是,为每个函数使用一个新域会引入大量开销。我的作业似乎表明开销最小,而且在某些情况下,域的性能实际上比try-catch要好。

http://www.lighthouselogic.com/#/using-a-new-domain-for-each-async-function-in-node/

我最近在http://snmaynard.com/2012/12/21/node-error-handling/.0.8版本中node的一个新功能是域,它允许您将所有形式的错误处理合并到一个更简单的管理表单中。您可以在我的文章中阅读它们。

您还可以使用Bugsnag之类的工具来跟踪未捕获的异常,并通过电子邮件、聊天室或创建未捕获异常的罚单(我是Bugsnag的联合创始人)获得通知。

使用try-catch可能比较合适的一个例子是使用forEach循环。它是同步的,但同时不能只在内部范围中使用return语句。相反,可以使用try-and-catch方法在适当的范围内返回Error对象。考虑:

function processArray() {
    try { 
       [1, 2, 3].forEach(function() { throw new Error('exception'); }); 
    } catch (e) { 
       return e; 
    }
}

这是上面@balupton描述的方法的组合。

如果你想在Ubuntu中使用服务(Upstart):在Ubuntu 11.04中使用节点作为服务,包括Upstart、monit和forever.js