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


73

当没有任何异常抛出时,使用多个try-catch块是否“缓慢”?我的问题与这一问题相同,但对于JavaScript。

假设我有20个在其中具有try-catch块的函数,以及另一个函数,在这20个函数中的每个函数都调用时,它们都不抛出异常。由于有try-catch块,我的代码执行速度会变慢还是变差?



1
@Chase:但是那不是谈论捕获异常的时间吗?
澳洲航空94重型

2
@ Qantas94Heavy-在jsperf上有很多不错的Try / Catch性能测试:jsperf.com/search?q= Try/Catch 。在大多数情况下,try可以忽略不计,但这取决于您对的定义slow。如果您正在寻找性能,那么还有更多更好的选择try/catch。@Roland很好地列出了一些不使用它们的充分理由。
大通

2
@Chase好吧,有99%的jsperfs都坏了,有时它们会误导人们并且不提供有用的信息。当然,几乎不执行任何操作的函数通过try catch只会稍微慢一些。
Esailija 2013年

2
因此,根据另一个答案,即我问题的简短答案,从那我必须突出显示从不抛出异常的时间为否,如果没有抛出异常,这并不昂贵。
cprcrack

Answers:


65

您在执行典型的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
}

在V8第6版(Node 8.3和最新的Chrome附带)之后,内部代码的性能try-catch与普通代码相同。


6
如果V8就是这种情况,那确实会有所作为,并且您的代码看起来像是解决该问题的好主意。您能否提供一个包含该信息源的链接,以表明V8不能使用try-catch块优化功能?您知道这是否适用于其他Javascript编译器或解释器吗?
cprcrack

5
@cprcrack我不确定,尝试在服务器端最需要catch,因此优化并不是优先考虑的事情。对于V8源代码,请参见此处,在优化编译器看到尝试捕获功能时无法解决问题github.com/v8/v8/blob/master/src/hydrogen.cc#L3922-L3927
Esailija

1
“但是,并非所有函数都可以被优化-某些功能会阻止优化编译器在给定函数上运行(“纾困”)。尤其是,当前优化编译器对使用try {} catch {}块的函数进行了优化!” 资料来源:html5rocks
ruhong 2015年

6
为了使答案保持最新,应该注意的是,尽管将V8 TurboFan编译器安装到Chrome和Node尚需几个月的时间,但仍将支持try-catch优化。参见例如codereview.chromium.org/1996373002
csvan

49

最初的问题询问未抛出错误时尝试/捕获的成本。使用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基本上是零惩罚。


8
唯一实际通过信息而非观点提供答案的答案。
BornReady

1
对我而言,尝试不捕获是最快的代码段,请参见fs5.directupload.net/images/170124/3luf37n3.png
timaschew

1
firefox 50似乎已经进行了尝试/捕获优化,但是chrome 55仍然没有,这是chrome fs5.directupload.net/images/170124/uak7g2j8.png
timaschew


jsperf在几年前脱机。没什么可做的。
哮喘

9

try-catch块被认为是昂贵的。但是,如果关键性能不是问题,那么使用它就不必担心。

IMO的罚款为:

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

可读性:使用大量的try-catch来检查代码很丑陋,分散注意力

不适当的:如果您的代码没有发生异常崩溃,则插入这样的块是一个坏主意。仅当您期望代码失败时才插入它。看一下以下主题:何时使用try / catch块?

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

希望这可以帮助,

R.


15
传闻说“据说是”。请提供证据,不要鼓励程序员过早地进行优化。
戴夫

7
这是胡扯。有许多不是“失败”的“例外”情况。异常是功能强大的编程构造。
squarewav 2014年

1
我测试了假设变量是可调用的性能,而不是先测试它。使用if语句进行验证比通过try / catch乞求宽恕要快几个
Joseph Sheedy

4
关于异步功能的适当性,现在基本上是将try catch与ES7 async await结合使用的默认设置。您可能需要更新您的答案以反映最近的发展。
Florian Wendelborn

1
与异步回调的错误处理相比,try / catch方法的另一个重要意义是,在异步回调中错误地在错误处理代码中抛出(例如,输入错误或难以错过的逻辑错误)可能会使进程崩溃,而意外地抛出(例如拼写错误或难以错过的逻辑错误)catch不会出现在块中。await通过承诺链尝试/捕获与错误处理相比,还有明显的优势,但这超出了本文的范围。有关更多信息:gist.github.com/mikermcneil/c1028d000cc0cc8bce995a2a82b29245
mikermcneil

0

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

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

  • (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)在运行时几乎相等。尝试捕获(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 ++的上下文中,但此处也适用相同的课程。如果我没记错的话,我的讲师说试块的设计非常高效,几乎是看不见的。但是,这是一个很慢的陷阱,我的意思是真的很慢。如果抛出错误,则使用catch块进行处理的时间要比使用if-else块所完成的处理时间长数百倍甚至数千倍。因此,请保持例外情况例外

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.