本文通过对比实验分析 JavaScript 中 try-catch 语句对代码执行性能的影响。测试结果显示,无论代码位于 try 还是 catch 块,其性能消耗基本一致。主要性能损耗源于 JS 引擎在进入 try-catch 时拷贝当前词法环境(Scope)。建议将耗时代码封装为独立函数并通过调用执行,以减少变量拷贝带来的开销。
前言与背景
前言
过去对于 try-catch 对代码运行性能的具体影响,我仅停留在直观感受层面,并未深入探究。近期在一次技术交流会议中,有人提出了关于此问题的疑问。借此机会,利用周末时间进行了一次专项研究。
前端线上脚本错误的捕获方法:
window.JSTracker=window.JSTracker||[];
try{
//your code
}catch(e){
JSTracker.push(e);
throwe;//建议将错误再次抛出,避免测试无法发现异常
}
实验设计与方法
设计实验方式
采用简单的对比实验方案。
空白组1:[无 try catch 的情况下对数据取模1千万次耗时]
<!DOCTYPEhtml>
<html>
<head>
<title>1无trycatch的情况耗时</title>
<script>
!function(){
//无try catch的情况耗时
vart=newDate();
//耗时代码开始
for(vari=0;i<100000000;i++){
varp=i%2;
}
//耗时代码结束
document.write(newDate()–t);
}();
</script>
</head>
<body>
</body>
</html>
参照组2:[将耗时代码用 try 包围,内联耗时代码]
<!DOCTYPEhtml>
<html>
<head>
<title>2在try中内联代码的耗时情况</title>
<script>
!function(){
//在 try 中内联代码的耗时情况
vart=newDate();
try{
//耗时代码开始
for(vari=0;i<100000000;i++){
varp=i%2;
}
//耗时代码结束
thrownewError();
}catch(e){
}
document.write(newDate()–t);
}();
</script>
</head>
<body>
</body>
</html>
参照组3:[将耗时代码用 try 包围,外联耗时代码]
<!DOCTYPEhtml>
<html>
<head>
<title>3在try中内联代码的耗时情况</title>
<script>
!function(){
functionrun(){
//耗时代码开始
for(vari=0;i<100000000;i++){
varp=i%2;
}
//耗时代码结束
}
//在 try 中内联代码的耗时情况
vart=newDate();
try{
run();
thrownewError();
}catch(e){
}
document.write(newDate()–t);
}();
</script>
</head>
<body>
</body>
</html>
参照组4:[将耗时代码用 catch 包围,内联耗时代码]
<!DOCTYPEhtml>
<html>
<head>
<title>4在catch中内联代码的耗时情况</title>
<script>
!function(){
//在 catch 中内联代码的耗时情况
vart=newDate();
try{
thrownewError();
}catch(e){
//耗时代码开始
for(vari=0;i<100000000;i++){
varp=i%2;
}
//耗时代码结束
}
document.write(newDate()–t);
}();
</script>
</head>
<body>
</body>
</html>
参照组5:[将耗时代码用 catch 包围,外联耗时代码]
<!DOCTYPEhtml>
<html>
<head>
<title>5在catch中内联代码的耗时情况</title>
<script>
!function(){
functionrun(){
//耗时代码开始
for(vari=0;i<100000000;i++){
varp=i%2;
}
//耗时代码结束
}
//在 catch 中内联代码的耗时情况
vart=newDate();
try{
thrownewError();
}catch(e){
run();
}
document.write(newDate()–t);
}();
</script>
</head>
<body>
</body>
</html>
运行结果(只选取了 Chrome 作为示例)
| – | 不使用 TRY-CATCH | TRY 中耗时,内联代码 | TRY 中耗时,外联代码 | CATCH 中耗时,内联代码 | CATCH 中耗时,外联代码 |
| Chrome51 | 98.2 | 1026.9 | 107.7 | 1028.5 | 105.9 |
性能影响总结与建议
给出总结
实验表明,无论代码是放置在 try 块中还是 catch 块中,其带来的性能消耗是相同的。
需要特别注意的性能损耗点在于:避免在 try-catch 块中直接编写大量代码(尤其是声明过多变量)。最佳实践是将所有需要执行的逻辑封装在另一个 function 中,通过调用该函数来执行具体任务。
关于第二点的原理,可以参考 ECMA 规范中关于 try-catch 的解释:当代码进入 try-catch 结构时,JavaScript 引擎会拷贝当前的词法环境(Lexical Environment)。所谓“拷贝”,实际上就是复制当前 Scope 下的所有变量信息。
建议
在使用 try-catch 时,尽量将其置于一个相对“干净”的作用域中。同时,在 try-catch 语句内部应尽量减少变量的声明数量。最推荐的做法是通过函数调用的方式来包裹 try-catch 逻辑。
异常现象原理分析
试验中的现象解释
在测试过程中发现一个值得注意的现象:以下两段代码在 Chrome 44 版本中运行结果差异巨大。仅添加一句空的 try-catch 后,平均耗时约为 850ms;而未添加前耗时约为 140ms。
!function(){
//无 try catch 的情况耗时
vart=newDate();
//耗时代码开始
for(vari=0;i<100000000;i++){
varp=i%2;
}
//耗时代码结束
document.write(newDate()–t);
try{
}catch(e){
}
}();
!function(){
//无 try catch 的情况耗时
vart=newDate();
//耗时代码开始
for(vari=0;i<100000000;i++){
varp=i%2;
}
//耗时代码结束
document.write(newDate()–t);
}();
其实原因很简单
只要将代码结构调整为如下形式,耗时即可显著降低:
!function(){
!function(){
//无 try catch 的情况耗时
vart=newDate();
//耗时代码开始
for(vari=0;i<100000000;i++){
varp=i%2;
}
//耗时代码结束
document.write(newDate()–t);
}();
try{
}catch(e){
}
}();
总结
以上就是关于使用 try-catch 对代码运行性能影响的全部内容,希望本文的内容对大家学习或者使用Javascript能带来一定的帮助,如果有疑问大家可以留言交流。