25

如果您查看域的 Node.js 文档的开头,它会指出:

由于 throw 在 JavaScript 中的工作原理,几乎没有任何方法可以安全地“从上次中断的地方继续”,而不会泄漏引用或创建其他类型的未定义脆弱状态。

同样在代码示例中,它在第一部分给出了它说:

尽管我们已经阻止了突然的进程重启,但我们正在疯狂地泄漏资源

我想了解为什么会这样?哪些资源正在泄漏?他们建议您仅使用域来捕获错误并安全地关闭进程。这是所有例外的问题,而不仅仅是在使用域时?在 Javascript 中抛出和捕获异常是一种不好的做法吗?我知道这是 Python 中的一种常见模式。

编辑

如果抛出异常,我可以理解为什么在非垃圾收集语言中可能存在资源泄漏,因为如果抛出异常,您可能运行来清理对象的任何代码都不会运行。

我可以用 Javascript 想象的唯一原因是,如果抛出异常会将对变量的引用存储在引发异常的范围内(可能还有调用堆栈中的东西),从而保持引用,然后异常对象被保留并且永远不会被清理干净。除非提到的泄漏资源是引擎内部的资源。

更新

我写了一篇博客,现在更好地解释了这个问题的答案。看看这个

4

3 回答 3

14

意外的异常是您需要担心的。如果您对应用程序的状态不够了解,无法添加对特定异常的处理并管理任何必要的状态清理,那么根据定义,您的应用程序的状态是未定义且不可知的,并且很可能存在一些事情不应该在附近闲逛。您需要担心的不仅仅是内存泄漏。未知的应用程序状态可能会导致不可预知的和不需要的应用程序行为(例如提供错误的输出——部分呈现的模板,或不完整的计算结果,或者更糟糕的是,每个后续输出都错误的情况)。这就是为什么在发生未处理的异常时退出进程很重要的原因。它使您的应用程序有机会自我修复。

发生异常,这很好。拥抱它。关闭该过程并使用Forever之类的东西来检测它并使事情重回正轨。集群和域也很棒。您正在阅读的文本并不是对抛出异常的警告,或者在您处理预期的异常时继续该过程 - 它是在发生意外异常时不要保持进程运行的警告。

于 2013-04-08T08:02:43.957 回答
11

我认为当他们说“我们正在泄漏资源”时,他们的真正意思是“我们可能正在泄漏资源”。如果 http.createServer 适当地处理异常,线程和套接字不应该被泄露。但是,如果它不能正确处理事情,它们当然可能是这样。在一般情况下,您永远不会真正知道某些东西是否始终正确处理错误。

我认为当他们说“由于 throw 在 JavaScript 中的工作原理,几乎没有任何方法可以安全地…… ”时,他们是错误的/非常具有误导性。不应该有任何关于 throw 在 Javascript(相对于其他语言)中如何使其不安全的事情。也没有关于 throw/catch 的一般工作方式使其不安全的任何内容 - 当然除非你错误地使用它们。

他们应该说的是,异常情况(无论是否使用异常)都需要妥善处理。有几个不同的类别需要识别:

一个状态

  1. 外部状态(数据库写入、文件输出等)处于瞬态时发生的异常
  2. 共享内存处于瞬态时发生的异常
  3. 只有局部变量可能处于瞬态的异常

B. 可逆性

  1. 可逆/可逆状态(例如数据库回滚)
  2. 不可逆状态(丢失数据、未知如何反转或禁止反转)

C. 数据关键性

  1. 数据可以报废
  2. 必须使用数据(即使已损坏)

无论您正在搞乱哪种状态,如果您可以反转它,您应该这样做并且您已经设置好了。问题是不可逆的状态。如果您可以销毁损坏的数据(或将其隔离以单独检查),那是不可逆状态的最佳举措。当抛出异常时,本地变量会自动执行此操作,这就是为什么异常擅长处理纯函数式代码中的错误(即没有可能的副作用的函数)。同样,如果可以接受,则应删除任何共享状态或外部状态。在共享状态的情况下,要么抛出异常,直到该共享状态变为本地状态并通过展开堆栈(静态或通过 GC)来清理,要么重新启动程序(我读过有人建议使用某些东西永远喜欢nodejitsu)。

最后一种情况是数据至关重要的时候。好吧,那么你将不得不忍受你创造的错误。每个人都必须处理错误,但当您的错误涉及损坏的数据时,这是最糟糕的。这通常需要人工干预(重建丢失/损坏的数据,选择性地修剪等)——在最后一种情况下,异常处理不会让你全部完成。

我写了一个类似的答案,与如何在对某些数据存储进行多次更新的情况下在各种情况下处理中间操作失败有关:https ://stackoverflow.com/a/28355495/122422

于 2013-04-10T06:50:15.500 回答
8

从 node.js 文档中获取示例:

var d = require('domain').create();
d.on('error', function(er) {
  // The error won't crash the process, but what it does is worse!
  // Though we've prevented abrupt process restarting, we are leaking
  // resources like crazy if this ever happens.
  // This is no better than process.on('uncaughtException')!
  console.log('error, but oh well', er.message);
});
d.run(function() {
  require('http').createServer(function(req, res) {
    handleRequest(req, res);
  }).listen(PORT);
});

handleRequest在这种情况下,当您关闭套接字之前发生异常时,您正在泄漏连接。

“泄漏”是指您完成了对请求的处理而没有事后清理。最终连接将超时并关闭套接字,但如果您的服务器处于高负载状态,它可能会在此之前用完套接字。

根据您所做的工作,handleRequest您还可能会泄漏文件句柄、数据库连接、事件侦听器等。

理想情况下,您应该处理您的异常,以便您可以在它们之后进行清理。

于 2013-04-08T10:21:34.207 回答