在Javascript中,即使从不抛出异常,使用try-catch块也是昂贵的吗?

cpr*_*ack 52 javascript performance exception-handling exception try-catch

当没有任何异常被抛出时,使用几个try-catch块是"慢"吗?我的问题与问题相同,但对于Javascript.

假设我有20个函数,其中包含try-catch块.另一个函数调用这20个函数中的每一个.他们都不会抛出异常.由于这个try-catch块,我的代码执行速度会慢还是执行得更差?

Esa*_*ija 52

你在做典型的CRUD UI代码吗?使用try catch,使用循环到10000,无缘无故地洒在你的代码中,地狱,使用angular/ember - 你不会注意到任何性能问题.

如果您正在进行低级库,物理模拟,游戏,服务器端等,那么永远不会抛出的try-catch块通常根本不重要,但问题是V8在它们的优化编译器中不支持它直到版本6对于引擎,所以语法上包含try catch的整个包含函数将不会被优化.您可以通过创建辅助函数来轻松解决此问题tryCatch:

function tryCatch(fun) {
    try {
        return fun();
    }
    catch(e) {
        tryCatch.errorObj.e = e;
        return tryCatch.errorObj;
    }
}
tryCatch.errorObj = {e: null};


var result = tryCatch(someFunctionThatCouldThrow);
if(result === tryCatch.errorObj) {
    //The function threw
    var e = result.e;
}
else {
    //result is the returned value
}
Run Code Online (Sandbox Code Playgroud)

在V8版本6(随Node 8.3和最新的Chrome一起提供)之后,内部代码的性能与普通代码的性能try-catch相同.

  • 如果是V8就是这种情况,那真的会有所不同,而且你的代码看起来是个好主意来解决这个问题.您是否可以提供指向V8未使用try-catch块优化函数的信息来源的链接?你知道这是否适用于其他Javascript编译器或口译员? (6认同)
  • @cprcrack我不确定,在服务器端主要需要尝试catch,因此优化并不是一个重要的优先事项.请参阅此处查看V8源代码,其中优化编译器在函数中看到try catch时会失败https://github.com/v8/v8/blob/master/src/hydrogen.cc#L3922-L3927 (5认同)
  • 为了使答案保持最新,应该注意的是新的V8 TurboFan编译器将支持try-catch优化,尽管从使用它进入Chrome和Node还需要几个月的时间.参见例如https://codereview.chromium.org/1996373002 (5认同)

ast*_*mas 38

最初的问题是在没有抛出错误时询问try/catch的成本.使用try/catch保护代码块时肯定会产生影响,但是当受保护的代码变得更加复杂时,try/catch的影响将很快消失.

考虑这个测试:http://jsperf.com/try-catch-performance-jls/2

一个简单的增量运行每秒356,800,000次迭代try/catch中的相同增量是每秒93,500,000次迭代.由于try/catch,这是75%的开销.但是,一个简单的函数调用每秒运行112,200,000次迭代.2个简单的函数调用以每秒61,300,000次迭代运行.

在此测试中未执行的尝试比一个简单的函数调用花费更多的时间.除了在像FFT这样真正强烈的内部循环之外,这几乎不是速度惩罚.

您要避免的情况是实际抛出异常的情况.这非常慢,如上面的链接所示.

编辑:这些数字适用于我的计算机上的Chrome.在Firefox中,未执行的尝试与根本没有保护之间没有显着差异.如果没有抛出异常,使用try/catch基本上没有任何惩罚.

  • 实际上通过信息而非意见提供答案的唯一答案. (4认同)

rol*_*and 8

try-catch块被认为是昂贵的.但是,如果关键性能不是问题,使用它不一定是一个问题.

罚款IMO是:

  • 可读性
  • 在许多情况下不合适
  • 在异步编程方面无效

可读性:使用大量的try-catch来管理代码是丑陋和分散注意力的

不合适:如果你的代码不受异常崩溃的影响,插入这样的块是个坏主意.只有在您的代码中出现故障时才插入它.看一下以下主题:何时使用try/catch块?

异步:try-catch块是同步的,在async编程时无效.在ajax请求期间,您可以处理专用回调中的事件errorsuccess事件.没必要try-catch.

希望这可以帮助,

R.

  • "据说是"传闻.请提供证据,不要鼓励程序员过早优化. (11认同)
  • 这是蠢货.有许多"特殊"情况并非"失败".例外是一种强大的编程结构. (7认同)
  • 关于异步函数的适当性,现在基本上默认使用try catch结合ES7异步等待.您可能希望更新您的答案以反映最近的发展. (3认同)

Aks*_*lén 7

我试图根据具体的基准测试结果提供答案。为此,我编写了一个简单的基准测试,将 try-catch 与从简单到更复杂的各种 if-else 条件进行比较。我知道基准可能会因平台而异。如果您得到不同的结果,请发表评论。请参阅此处try-catch 基准测试

首先,我尝试以紧凑的方式表示这里的测试套件。有关完整详细信息,请参阅上面的链接。有四个测试用例,后面由(index)引用:

  • (1) try-catch 块,它调用lib.foo带有一些三角数学的函数。永远不会抛出任何错误。
  • (2) if-else 块,通过检查函数是否存在,'foo' in lib然后调用该函数。
  • (3) if-else 块,检查函数是否存在,typeof lib['foo'] === 'function'然后调用该函数。
  • (4) if-else 块,通过检查函数是否存在,Object.prototype.hasOwnProperty.call(lib, 'foo')然后调用该函数。

我在 Chrome 87 上跑了几次基准测试。 虽然实际数字不时变化,但结果是一致的,可以大致总结如下:

  • try-catch (1) 和 if-else (2) 在运行时几乎相同。try-catch (2) 有时会慢 1% 到 2%。
  • if-else (3) 比 try-catch (1) 或 if-else (2) 慢 75%。
  • if-else (4) 比 try-catch (1) 或 if-else (2) 慢 90%。

澄清一下,慢 75% 意味着如果最快的情况需要 1.0 秒,那么慢 75% 的执行需要 1.75 秒。

总之,在永远不会抛出错误的情况下使用 try-catch 似乎与检查任何简单条件一样有效。如果条件有任何更复杂的情况,try-catch 会明显更快。

作为个人笔记,结论与我在大学所教的内容一致。虽然它是在 C++ 的上下文中,但同样的教训似乎也适用于这里。如果我没记错的话,我的讲师说 try-block 的设计非常高效,在效率方面几乎是隐形的。然而,是catch-block 很慢,我的意思是真的很慢。如果抛出错误,那么使用 catch-block 的处理时间比使用 if-else 块所能达到的时间长数百甚至数千倍。因此,请保持您的异常异常