JavaScript的try/catch:错误还是异常?

11

好的,也许我在这里有些钻牛角尖了,但我的代码并不一致,我想让它变得一致。但在这样做之前,我想确保我走的是正确的路。实际上这并不重要,但已经困扰我一段时间了,所以我觉得问问我的同行们...

每次我使用 try... catch 语句,在 catch 块中我总是将消息记录到我的内部控制台。但是我的日志消息并不一致。它们要么像这样:

catch(err) {
DFTools.console.log("someMethod caught an error: ",err.message);
...

或:

catch(ex) {
DFTools.console.log("someMethod caught an exception: ",ex.message);
...

显然,这段代码两种写法都能正常运行,但我有时会用“错误(errors)”有时会用“异常(exceptions)”,这开始让我感到困扰。也许我太过微辞了,但哪个术语才是正确的呢?是“异常(Exception)”还是“错误(Error)”?


我一直将其称为“异常处理”,但要触发catch块,您需要throw new Error("...") - Josh
5
您可以随意抛出任何内容 - throw "Hi Mom!";是完全有效的。 - Pointy
是的。也许我应该说抛出新的Error对象,或者继承自Error的对象。 - Josh
6个回答

11

这可能有点主观,但对我而言,错误是指某人或某物做错、不当或无效的事情。 它可以是语法错误、逻辑错误、读取错误、用户错误,甚至是社交错误。 这是一个抽象的概念。

另一方面,异常是在代码中发生某种条件时创建并抛出的对象。 它可能与概念上的错误相对应,也可能不相对应。 因此,对我而言,正确的术语是“异常”(exception)。


我喜欢这个 - 这让我感到很有道理 - Josh
3
好的。和朋友讨论过后,我正在认真考虑接受这个答案。我的想法是:结合你所说的和 @Pointy 在评论中提到的:你可以 throw 任何东西,catch 捕获的是异常。可能这个异常是错误。因此,“Exception” 是合适的术语。 - Josh
谢谢。我今天的声望限制已经达到了,所以请随意花费您需要的时间。 - tloflin
很好。我会稍后接受,这样更多的人有机会参与讨论。 - Josh
异常不是期望的错误,而错误是意外的。 - David R.

4

ECMAScript规范称其为异常。您可能也希望这样做。

为了使您的日志记录更具信息性:

catch(ex) {
    DFTools.console.log("someMethod caught an exception of type " 
       + ex.name + ": ", ex.message);

您还需要记住的是,异常(不幸的是)可以是任何类型,因此不一定具有 namemessage 属性:

catch(ex) {
    if (ex.message && ex.name) {        
        DFTools.console.log("someMethod caught an exception of type " 
           + ex.name + ": ", ex.message);
    } else /* deal with it somehow */

由于在各处重复这个代码显得非常笨重,你可能想将它捕获到一个函数中:

function logExceptions(methodName, action) {

    try {

        action();

    } catch (ex) {
        if (ex.message && ex.name) {        
            DFTools.console.log("someMethod caught an exception of type " 
               + ex.name + ": ", ex.message);
        } else {
            DFTools.console.log("someMethod caught a poorly-typed exception: " + ex);
        }
    }
}

现在你可以说:
logExceptions(function() {

    // do some risky stuff...

});

哈!实际上,ECMAScript规范将其称为“错误异常”! - Josh
2
是的,所有标准异常构造函数都使用Error而不是Exception...但这就是JS! :) 但这也许是因为这些异常函数应该指示错误;异常的其他用途可能不是。例如,在Mozilla的JavaScript 1.7中,有一个名为“generators”的扩展使用异常来指示序列的结束,异常类型是StopIteration - 没有提到“错误”,这是有道理的。所以这种疯狂的方法可能有一些方法... - Daniel Earwicker
@Josh - 我上面的回复是针对你编辑之前的原始评论,你问为什么内置异常构造函数使用单词“Error”。新的回复是:你在看哪个规范?我链接的版本将异常称为“exceptions”。它使用术语“error exception”来特指指示错误的异常,而不是所有异常。 - Daniel Earwicker
1
@Daniel:抱歉,我在阅读完整个内容之前就发布了评论,所以我编辑了我的评论。现在我看到规范中定义了“错误”、“异常”和“错误异常”...这让我认为我应该彻底更改我的代码,以检测捕获的对象是一个错误还是一个异常... - Josh
1
好的 - 我的意思是,如果你在日志中包含 ex.name,你就能够看到它是否是一个错误或其他问题,而无需以任何其他方式对其进行分类。此外,我还添加了一些处理其他问题的想法。 - Daniel Earwicker
显示剩余3条评论

1
主要声明:我认为没有“正确”的答案。这里所表达的观点是主观和个人的。更重要的是,我即将阐述的想法只有在您使用不同的系统和错误时才有用,例如按照Daniel Earwicker信息性答案的方式。考虑到这一点:

我认为“异常是例外”。错误比较不出乎意料。

免责声明:以下伪代码并不好,它仅仅作为我能想到的最小案例来说明我的观点。 注意:在这个思想实验中,如果无法找到指定的文件,则GetFile返回UNDEFINED。
function AlwaysGetFile(name){
    var file = null;
    if(FileExists(name)){
        file = GetFile(name);
        if(typeof file === "undefined"){
            throw new "couldn't retrieve file" EXCEPTION
        }
    }
    else{
        throw new "file does not exist" ERROR
    }
    return file;
}

如果消费者使用不存在的文件名调用GetFileOrThrow,则会出现错误。在我看来,区别实际上是更高级别的代码(或用户输入)在做错事情...这个函数必须将错误传递给那个高级别的代码,该代码可以决定如何处理此结果。想象一下...这个函数会对任何消费函数说:
“听着,朋友,我知道这里发生了什么:请求BobAccounts.xml是一个错误,所以不要再试了!哦,如果你认为你现在知道可能出了什么问题(因为滥用了我),那就试着从中恢复吧!”
现在考虑这个函数接受名称、检查文件是否存在,然后由于某种原因无法检索它的情况。这是一种不同的情况。真正意外的事情发生了。更重要的是,消费代码没有责任。现在我们真的希望这个函数对任何消费函数说:
抱歉,出了点问题,我不明白发生了什么异常情况。我认为您请求BobAccounts.xml并不过分,我应该满足您的需求。由于我的级别比您低,所以我真的应该知道发生了什么事情,但我不知道。既然您比我更难理解这个异常情况,最好停止您正在做的事情,并让这个消息传到最高层……我的意思是,这里有一些非常可疑的事情发生了。
因此,我的结论是:如果错误发生在高级代码中(您收到了错误数据),则抛出错误。如果错误发生在低级代码中(您依赖的函数以您无法理解和计划的方式失败),则抛出异常......如果错误发生在您当前编写的函数中......那么,嗯,如果您意识到了它,请修复它!
最后,为了更直接地回答原问题:在处理错误和异常方面,我的建议是:优雅地处理所有错误(可选择记录它们)...但确实要小心处理异常;只有在确信知道发生了什么以及为什么发生时,才尝试从异常中恢复,否则让其冒泡(必要时重新抛出异常)。

1

异常是一些你可能预料到的情况,例如尝试打开一个文件时可能会遇到“文件未找到异常”。另一方面,错误是一些你可能没有预见到的情况,比如堆栈溢出或内存不足。

异常是函数中的一种替代逻辑方式,它不会产生逻辑结果。异常还允许更好地解释发生了什么以及为什么会出现这种情况。对于文件打开,文件句柄是一个逻辑结果,如果文件不存在(可能是一个异常)或者它是一个文件夹而不是一个文件(另一个可能的异常)。


+1:这与我对该主题的看法类似。可以预期会出现异常,但错误则不应该。 - CAbbott
所以如果我理解你的意思正确,你建议我根据实际发生的情况进行日志记录?也就是说,我确定何时出现错误和异常?例如,如果它是围绕AJAX调用的try/catch块,则为异常,但内存不足错误则是错误? - Josh
异常是函数的一种替代方式,它不会产生逻辑结果。异常还允许更好地解释发生了什么以及为什么存在这种情况。对于文件打开,文件句柄是一个逻辑结果,如果文件不存在(可能是一个异常)或者它是一个文件夹而不是一个文件(另一个可能的异常)。这种情况下我将使用异常。因此,AJAX调用应该抛出异常。:-D - NawaMan

1
在JavaScript中,它被称为错误捕获。因此,我建议您使用错误而不是异常。 通过在Mozilla的示例中使用“e”来保持选择中立。 Mozilla Core JavaScript 1.5 Reference

1
啊...但是http://w3schools.com/js/js_throw.asp说:“throw语句允许您创建异常。” - Josh
2
w3schools是一组教程,而不是一个权威的参考网站。 - Daniel Earwicker
你可以抛出一个异常。catch语句将该异常捕获为错误。至少这是W3C的描述,维基百科和Mozilla也是如此。 - ReinierDG

0
在 Catch 块中获取的是异常,因此我将其命名为异常...
如果是错误 - 我可以在我的代码中处理它,通常不希望在 Catch 块中看到它。
希望对你有所帮助。

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