为什么JavaScript中很少使用Try/Catch?

39

似乎其他支持Try/Catch的编程语言中,开发者比在JavaScript中更频繁地使用该功能。这是为什么呢?JS中的Try/Catch实现存在缺陷吗?


1
我的猜测是人们不知道它或者不知道如何使用它。或者,有时候通过简单的检查,你可以避免使用 try,如果你能在它失败之前检测到它将会失败的话。 - gen_Eric
3
它们确实存在,不过没有它们JavaScript更好。 - geekman
6
在JavaScript中,使用try-catch块可以捕获并处理代码中的异常。尽管有些人认为这是一种良好的实践方法,但其他人则认为这样做可能会对代码性能和可读性产生负面影响。总的来说,是否使用try-catch应该取决于具体情况和编程需求。 - Andreas
我的意思是这不是一些需要检查错误的高级编码,你正在操作DOM,捕获事件,如果出了问题就会停止,即使捕获异常也会停止。 - geekman
1
@I-love-php - 记住 JavaScript 也可以用于其他方面(参见 Node.js)。 - Hogan
5个回答

41
尝试查看这篇文章:http://dev.opera.com/articles/view/efficient-javascript/?page=2#trycatch 从上面的链接中:
try-catch-finally结构是相当独特的。与其他结构不同,它在运行时在当前作用域中创建一个新变量。每次执行catch子句时都会发生这种情况,其中捕获的异常对象被分配给一个变量。即使在同一作用域内,该变量也不存在于脚本的其他部分中。它在catch子句的开头创建,然后在结尾处销毁。
由于此变量是在运行时创建和销毁,并且代表语言中的特殊情况,因此一些浏览器处理它的效率不高,在性能关键循环中放置catch处理程序可能会导致性能问题。
您还可以查看类似的问题here 更新 "添加链接到:https://github.com/petkaantonov/bluebird/wiki/Optimization-killers,因为它包含有关V8及其处理这些(和类似)结构的有用信息。
特别是:
目前无法优化的:
- 生成器函数 - 包含for-of语句的函数 - 包含try-catch语句的函数 - 包含try-finally语句的函数 - 包含复合let赋值的函数 - 包含复合const赋值的函数 - 包含proto、get或set声明的对象字面量的函数
可能永远无法优化的:
- 包含debugger语句的函数 - 调用literal eval()的函数 - 包含with语句的函数"

6
从性能角度来看,更糟糕的是,至少 V8 引擎不会优化带有 try-catch 的函数。因此,即使整个循环都在 try 块内完成,它也会变得更慢。通过将性能关键的循环放入其自己的函数中,并将 try-catch 放在外面,我在一个测试中提高了大约 10-15% 的性能。 - Matthew Crumley
没有任何catch的try-finally块会有性能损耗吗? - Nathan
1
@Nathan 在这里看:https://github.com/petkaantonov/bluebird/wiki/Optimization-killers 看来 V8 不支持 try-catch 和 try-finally 的优化。*某些结构根本不受优化编译器的支持,使用这样的语法将使包含函数无法优化。需要注意的是,即使该结构是不可达或不运行,这些结构仍会导致函数无法优化。* - Chase
4
更新:根据https://github.com/petkaantonov/bluebird/wiki/Optimization-killers的说法,除了第一个和最后一个之外,“目前无法优化”的所有结构现在都可以进行优化。 - tobek

15
不,它并没有缺陷,但对于同步代码来说,使用自己的代码检查事物通常比使用笨重的 try{}catch(e){} 更容易和清晰。
例子:
var container = document.getElementById("timmy");
container.innerHTML = "I'm timmy!";

如果没有ID为"timmy"的元素,我们可以这样处理:

try
{
    container.innerHTML = "I'm timmy";
}
catch (error)
{
    //handle no container
}

或者:

if(container) container.innerHTML = "I'm timmy";
else //handle no container

还有一件需要记住的事情是JavaScript应用程序是事件驱动的,而在程序主体中的try/catch块无法捕获发生在事件回调中的错误。

例如:

sqlConnection.query("SELECT * FROM table", 
    function(){console.log("queried!");});

这将触发一些本地代码,随着你的程序继续运行。如果发生错误,你不能期望你的程序返回到这一行,以便你的错误处理程序可以处理这个错误!相反,你在回调函数中处理错误。常见的做法是通过将其作为第一个参数传递来向回调函数提供任何发生的错误。

sqlConnection.query("SELECT * FROM table", 
    function(error, data){
        if(error) console.log("query failed");
        else console.log("queried!");
    });

或者,如果你的代码在回调中失败了,你可以按照我上面提到的方式处理它。

link.onclick = function(e)
{
    var popUp = document.getElementById("popup");
    if(!popUp)
        return true; //follow link if no pop-up exists
    popUp.style.display = "block";
};

2
如果您通过进行一些测试可以确保异常不会发生,那么就不需要使用try catch。在Javascript中只有少数情况需要测试/探测错误。 - Jeremy J Starcher

9
大多数JavaScript代码的异步性质隐藏了try/catch在低层级别上的处理,然后调用一个错误回调函数。
js中大部分繁重的代码是异步的,并使用回调函数或promise模式。其他代码比较简单,不需要try/catch。
如果你深入研究js库(选择你喜欢的),你会发现try/catch块包裹着许多现代js应用程序执行的繁重的应用代码。这些库然后调用错误或失败的回调,你在许多js代码示例中看到的那种回调。

1
我真的认为这是主要原因。大多数需要使用try/catch的错误都隐藏在各种库的深处。其他潜在的错误条件可以在尝试操作之前轻松检查。 - Jeremy J Starcher

2

我认为相较于 if 语句,try/catch 会有更多的开销,但只有当真正抛出异常时才会有影响。我经常使用 try/catch,但仅当我知道可能会抛出异常时。

如果使用得当,实际上没有理由不使用 try/catch。


0

JavaScript并不需要它们,原因是几乎没有必要捕获错误,因为一个错误并不会停止整个脚本。 Javascript是事件驱动的,大多数函数在特定事件发生时运行,并且它是客户端的,所以如果出了问题,就出了问题,捕获和处理错误几乎没有什么好处。 这只是我的看法。


考虑调用 A.func(),因为 JavaScript 是一种动态语言,具有运行时类型检查和后期绑定,在这种情况下无法保证 A 对象已附加函数 func()。这可能会引发错误,需要使用 try-catch 块来缓解。如果任何方法调用可能导致异常,您需要在代码中的某个位置捕获这些错误。不捕获它意味着您不知道应用程序正在做什么,并且在服务器端代码中可能会导致崩溃。 - Niels Joubert
1
@NielsJoubert 不需要try-catch,那只是你代码中的一个错误。你不需要“静态保证”。 - Esailija

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接