ChatGPT解决这个技术问题 Extra ChatGPT

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

当其中任何一个都没有引发异常时,使用多个 try-catch 块是否“慢”?我的问题与 this one 相同,但针对的是 JavaScript。

假设我有 20 个函数,其中包含 try-catch 块,另一个函数调用这 20 个函数中的每一个,其中没有一个会引发异常。我的代码会因为这个 try-catch 块而执行得更慢或更差吗?

@Chase:但这不是在讨论何时捕获异常吗?
@Qantas94Heavy - jsperf 上有很多不错的 Try/Catch 性能测试:jsperf.com/search?q=Try/Catch。在大多数情况下,try 可以忽略不计,但这在一定程度上取决于您对 slow 的定义。如果您正在寻找性能,那么有比 try/catch 更好的选择。 @Roland 很好地列出了一些不使用它们的好理由。
@Chase Well 99% 的 jsperfs 都被破坏了,在其他时候它们具有误导性并且不提供有用的信息。当然,一个几乎不做任何事情的函数使用 try catch 只会稍微慢一些。
因此,根据另一个答案,对我的问题的简短回答,从我必须强调什么时候永远不会抛出异常,是“否”,如果不抛出异常,它并不昂贵。

E
Esailija

你在做典型的 CRUD UI 代码吗?使用尝试捕获,使用无缘无故地在代码中散布到 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 内代码的性能与普通代码相同。


如果 V8 就是这种情况,那真的会有所作为,而且您的代码看起来是解决该问题的好主意。您能否提供一个链接,说明 V8 没有使用 try-catch 块优化功能的信息来源?你知道这是否适用于其他 Javascript 编译器或解释器吗?
@cprcrack我不确定,服务器端最需要try catch,因此优化不是一个重要的优先事项。有关 V8 源代码,请参见此处,当优化编译器在函数中看到 try catch 时会退出github.com/v8/v8/blob/master/src/hydrogen.cc#L3922-L3927
“但是,并非所有函数都可以优化 - 某些功能会阻止优化编译器在给定函数上运行(“纾困”)。特别是,优化编译器目前使用 try {} catch {} 块来处理函数!” Source: html5rocks
为了让答案保持最新,需要注意的是,新的 V8 TurboFan 编译器将支持 try-catch 优化,尽管它距离 Chrome 和 Node 还需要几个月的时间。参见例如codereview.chromium.org/1996373002
a
asthomas

最初的问题询问了未引发错误时 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 基本上是零惩罚。


唯一真正通过信息而不是意见提供答案的答案。
对我来说 try-no-catch 是最快的片段,请参阅 fs5.directupload.net/images/170124/3luf37n3.png
firefox 50 似乎已经进行了 try/catch 优化,但 chrome 55 仍然没有,这是 chrome fs5.directupload.net/images/170124/uak7g2j8.png 的屏幕截图
链接 jsperf.com/try-catch-performance-jls/2 不再起作用。
jsperf 几年前下线了。对此无能为力。
C
Community

据说 try-catch 块很昂贵。但是,如果关键性能不是问题,则使用它不一定是一个问题。

国际海事组织的处罚是:

可读性

在许多情况下不合适

在异步编程方面无效

可读性:用大量的 try-catch 来检查你的代码是丑陋和分散注意力的

不恰当:如果您的代码不受异常崩溃的影响,那么插入这样的块是个坏主意。仅当您预计代码失败时才插入它。查看以下主题:When to use try/catch blocks?

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

希望这可以帮助,

R。


“据说是”是道听途说。请提供证据,不要鼓励程序员过早优化。
这是胡说八道。有许多不是“失败”的“异常”情况。异常是一种强大的编程结构。
我测试了假设变量是可调用的与首先测试它的性能。使用 if 语句进行验证比使用 try/catch 请求宽恕要快几个数量级:jsperf.com/try-catch-performance-jls
关于 async 函数的适当性,现在基本上默认使用 try catch 和 ES7 async await 结合。您可能想要更新您的答案以反映最近的发展。
与使用异步回调的错误处理相比,try/catch 方法的另一个重要意义是,在异步回调中的错误处理代码中意外抛出(例如拼写错误或难以错过的逻辑错误)可能会使进程崩溃< /b>,而在 catch 块中意外抛出(例如拼写错误或难以错过的逻辑错误)不会。与通过承诺链进行错误处理相比,使用 await 进行尝试/捕获也有显着优势,但这超出了本评论的范围。更多信息:gist.github.com/mikermcneil/c1028d000cc0cc8bce995a2a82b29245
A
Akseli Palén

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

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

(1) 调用函数 lib.foo 的 try-catch 块,带有一点三角数学。不会抛出任何错误。

(2) if-else 块,通过 lib 中的 'foo' 检查函数是否存在,然后调用该函数。

(3) if-else 块,通过 typeof lib['foo'] === 'function' 检查函数是否存在,然后调用该函数。

(4) if-else 块,通过 Object.prototype.hasOwnProperty.call(lib, 'foo') 检查函数是否存在,然后调用函数。

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

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 进行的处理比使用 if-else 块所花费的时间长数百甚至数千倍。因此,请保持您的异常异常。


只是为了好玩,我尝试用 if (lib.foo) { 替换基准中的第 if ('foo' in lib) { 行,以防 in 昂贵地循环,虽然只有三个属性(也许它会在足够复杂的对象中改变?), lib.foo 检查in 慢 79%。奇怪[对我来说]。无论如何,是的,基准测试始终是真正找出答案的正确方法!感谢您设置一个。
@ruffin,lib ``` 中的 ``` 'foo' 是否检查空值和零?或者它只适用于未定义?只是古玩:)