在 Javascript 中,即使从未抛出异常,使用 try-catch 块是否昂贵
In Javascript, is it expensive to use try-catch blocks even if an exception is never thrown?
当其中没有抛出异常时,使用多个 try-catch 块是否"缓慢"?我的问题和这个问题一样,但针对JavaScript。
假设我有 20 个函数,其中有 try-catch 块,另一个函数调用这 20 个函数中的每一个,其中没有一个会引发异常。我的代码会因为这个 try-catch 块而执行得更慢还是性能更差?
您是否正在编写典型的 CRUD UI 代码?使用 try catches,使用无缘无故地洒在你的代码中的循环到 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
内部代码的性能与普通代码相同。
最初的问题是在没有抛出错误时尝试/捕获的成本。 使用 try/catch 保护代码块时肯定会有影响,但 try/catch 的影响会很快消失,因为受保护的代码变得稍微复杂。
考虑以下测试:http://jsperf.com/try-catch-performance-jls/2
一个简单的增量以每秒 356,800,000 次迭代的速度运行try/catch 中的相同增量为每秒 93,500,000 次迭代。 由于尝试/捕获,这是 75% 的开销。但是,一个普通的函数调用以每秒 112,200,000 次迭代的速度运行。2 个简单的函数调用以每秒 61,300,000 次迭代的速度运行。
在此测试中,未行使的尝试比一次琐碎的函数调用花费的时间略多。这几乎不是一个重要的速度惩罚,除了在像FFT这样非常激烈的东西的最内循环中。
要避免的情况是实际引发异常的情况。 这非常慢,如上面的链接所示。
编辑:这些数字适用于我机器上的Chrome。 在 Firefox 中,未行使的尝试和根本没有保护之间没有显着区别。 如果没有引发异常,则使用 try/catch 基本上不会受到任何惩罚。
我试图根据具体的基准测试结果提供一个答案。为此,我写了一个简单的基准测试,将 try-catch 与从简单到更复杂的各种 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 似乎与检查任何简单条件一样有效。如果情况有更复杂的情况,尝试捕获的速度要快得多。
就个人而言,结论与我在大学里所教的内容一致。虽然这是在C++的背景下,同样的教训似乎也适用于这里。如果我没记错的话,我的讲师说try-block的设计非常高效,在效率方面几乎看不见。然而,这是缓慢的捕获块,我的意思是真的很慢。如果抛出错误,那么使用 catch-block 处理所需的时间比使用 if-else 块可以实现的时间长数百倍甚至数千倍。因此,请保持例外情况。
try-catch
块很昂贵。但是,如果关键性能不是问题,则不一定是问题。
国际海事组织的处罚是:
- 可读性
- 在许多情况下不合适 在
- 异步编程方面无效
可读性:用大量的 try-catch 来探测你的代码是丑陋和分散注意力的
不合适:如果您的代码不受异常崩溃的影响,则插入此类块是一个坏主意。仅当您预计代码失败时才插入它。查看以下主题:何时使用 try/catch 块?
异步:try-catch
块是同步的,在async
编程时无效。在ajax
请求期间,您可以在专用回调中处理error
和success
事件。无需try-catch
.
希望这有帮助,
R.
- errors with Javascript try catch
- JSON.parse,已经在try/catch块中,仍然抛出语法错误
- Safari 在尝试使用 Javascript try/catch 访问父窗口对象时未捕获异常
- 与在异步回调链中使用 try catch 块相比,返回异常有什么优势
- 在 Javascript 中,即使从未抛出异常,使用 try-catch 块是否昂贵
- 使用 try catch(e) 进行浏览器功能检测
- 使用 window.onerror 和 try-catch 块处理错误之间的差异
- 在声明变量时使用 try catch
- 在PHP中使用Try-catch结构
- 当使用函数引用时,Coffeescapet会奇怪地转换try/catch/finally块
- 为什么不't JavaScript库更频繁地使用try-catch块
- 如何使用生成器在内部循环带有try-catch块的异步代码
- JavaScript:使用严格模式在try/catch中定义一个常量
- 我应该在使用(Bluebird)承诺的代码中完全消除try/catch吗?
- 使用try-catch检索嵌套属性的值.这是一个有效的方法吗?
- 为什么我需要避免在循环中使用try-catch-finally
- 什么时候应该在JavaScript中使用try/catch ?
- 为什么在创建音频元素时使用try catch ?
- 如何使用编码模式/框架在try-catch块中执行每个Javascript函数(或范围内的函数)
- 如何使用try, catch在错误处理中打印消息