投掷字符串而不是错误


77

由于我们可以用throwJavascript中的关键字抛出任何内容,因此我们不能直接抛出错误消息字符串吗?

有人知道有什么收获吗?

让我为此添加一些背景:在JavaScript世界中,人们通常依赖于参数检查,而不是使用try-catch机制,因此仅使用抛出致命错误是有意义的throw。不过,为了能够捕获某些系统错误,我必须对自己的错误使用其他类,并且我不应该创建Error的子类,而应该使用String。


1
虽然有可能,但这有意义吗?我宁愿捕获错误而不是字符串。
罗伯W


Exports.login =(req,res)=> {login(req).then(({{token,user})=> {res.send(token);})。catch(err => {if(typeof err = =='string'){res.status(401).send(err);} else {console.log(err); res.status(500).send('出问题了');}}); 我确实以这种方式处理错误,我也感到困惑,我是否以正确的方式来做。
阿迪尔

Answers:


53

可以随意抛出任何内容,但是请记住,如果捕获在您自己的代码之外,则可能期望使用完整的Error实例而不是纯字符串。


8
例如,它可能假定的.message属性Error是字符串,尝试在其上调用字符串方法,然后爆炸。
Mark Amery

4
可以,但我不会说这是“好”
2016年

5
这是一个糟糕的主意,因为这意味着您在没有堆栈跟踪的情况下将很难调试该错误。
本杰明·格林鲍姆

1
@BenjaminGruenbaum如果您在Chrome中抛出一个字符串,则会得到堆栈跟踪。例如,function a(){throw“ Hello World”; } a();`将具有如下所示的a @ main.js:4 (anonymous) @ main.js:7
堆栈跟踪

1
@Taurus谢谢,我不知道-现在尝试使用未在firefox中连接的调试器进行操作:)
Benjamin Gruenbaum

54

是的,您可以抛出其他值,但这不是一个好习惯

有人知道有什么收获吗?

字符串不是错误对象,并且不会传达任何有用的调试信息。Devtools依赖于此,例如创建错误的文件和行,该throw位置的stacktrace等,这些都可以作为Error对象的属性使用。

每当您想到抛出原始字符串值时,就抛出一个new Error("<the string>")替代。


10
值得注意的是,即使您抛出字符串,Chrome devtools也会打印堆栈跟踪。您失去了.stack对某些自动错误处理有用的属性(例如,在向服务器设置错误的自动报告以调试在生产中出现问题的错误时),但这更多的是边缘情况;如果您抛出字符串,则在浏览器中进行日常手动调试会很好。
Mark Amery

19

您知道,您可以在消息中抛出错误。

try {
    throw new Error("This is an error");
} catch (e) {
    alert(e.message); // This is an error
}

但是您实际上可以抛出字符串:

try {
    throw "This is an error";
} catch (e) {
    alert(e); // This is an error
}

4
抱歉,您的问题未明确。我知道所有这些都可以,但是我对直接使用String而不是使用Error对象的潜在问题感兴趣。
billc.cn 2012年

嗯,好的,然后看看Ianzz的评论。它总结了所有注意事项。但是我的建议仍然是Error使用自定义消息来抛出对象。它为您省去了检查错误类型以将其他本地生成的错误告诉“您的”错误的麻烦...当然,除非您是故意这样做的(然后可能将Error对象重新抛出catch作用域) 。
MaxArt 2012年

5

就像上面其他人提到的那样,如果您没有抛出Error对象,那么您必须具有try / catch块来捕获这些对象并适当地处理它们,否则会给调试带来很大的麻烦。

但是,当出于非错误处理目的(例如控制程序流)抛出错误时,这可能是throw无错误利用的有用方法。

当使用抛出来控制程序流时,它在任何语言中都可能效率低下,因为运行时通常会花很多时间来释放调用堆栈信息并序列化数据,以便其可用于用户范围。通过避免错误创建,可以避免这种性能下降。关键是您必须在调用堆栈上拥有一个知道如何处理这种情况的处理程序。例如,如果您throw {isHardStop: true, stopCode: SOME_CODE}设计了处理程序来检测到这种情况,则可以使一些代码变平或选择更简洁的语法。

您的梯子案例的处理程序可以如下所示:

try { ... } catch(thr) {
    if(!thr){
       // Is not Error or Json - Handle accordingly
    } else if(thr.isHardStop){
       // Handle the stop
    } else {
       // Most likely a real error. Handle accordingly
    }
}

不,如果您需要驱动程序流,则返回/解析一个可以处理程序流的值。有一个例外是例外。如果您无法恢复并且需要系统引发异常,那么这不是用于程序流程,而是用于异常处理。
Sukima

我同意错误和异常不应用于异常处理以外的目的。但是,在我的示例中,我只是抛出一个对象而不是实例化错误,因此,它仅使用try / catch机制进行替代流控制。性能损失应该可以忽略不计,但是可培训性不是理想的。话虽这么说,但我自己从来没有做过这件事,现在可能不会。相反,我可能会通过将逻辑包装在返回成功标识符和结果值的lambda中来使用Erlang / Elixir中使用的方法。
蒂莫西·奎因

3

尽管您可以抛出任何类型的数据,但在调试时这并不是最佳选择。JSError对象包含有关错误和消息的所有信息。而字符串只能包含一条消息。

这些附加信息包括:

  1. fileName:从哪个文件引发错误
  2. Linenumber从哪一行引发错误
  3. stacktrace:从哪个函数调用错误

例如,这是chrome devtools的堆栈跟踪:

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.