有没有办法阻止Javascript静默失败?

19

让我十分烦恼的一件事是Javascript在许多情况下都会悄无声息地失败。

(移除了一个例子,因为它混淆了我的问题)

很多时候,当我在Firebug控制台中输入错误时,会提示出错信息,但当它在页面脚本中运行时,它却悄无声息地失败,即使Firebug控制台处于活动状态并打开!

Crockford的JsLint可以捕捉其中的一些问题,但仍有许多问题无法捕捉。

难道没有一种方法可以在浏览器中启用更多的错误信息吗?

你能做到这一点而不使用javascript调试器环境吗?我发现调试器对我帮助不大。我通常会插入几个console.log()语句,并在一分钟内找到问题所在。让我烦恼的是,在Javascript中静默错误可能会长时间未被注意,或以完全不明显的方式显示出来。更加令人沮丧的是,测试控制台中的语句确实会产生错误,那么问题出在哪里呢?

顺便说一下,我也遇到了同样的异常问题,有人注意到了吗?经常我的throw new语句根本没有起作用。但如果我在控制台中输入相同的内容,它就可以。

感谢您的有益评论(第一条答案),但这不是我的问题。例如,在需要对类的参数进行过滤时,这些测试非常有用,当您不确定环境是否存在时。你不希望在你预期他们应该出现的地方测试属性或类;这只会使代码膨胀而没有原因。


什么是静默错误?当网页在浏览器中运行时,默认情况下所有JavaScript错误都是静默的,因为没有必要向站点访问者显示它们。 - Šime Vidas
1
我猜想,雅虎和谷歌的JavaScript专家们在做什么呢?他们有一个很棒的编译器,还有JsLint,但这还不够。我简直无法相信他们居然忍受这个。我一定是漏掉了什么。我正在努力弄清楚是否必须使用像微软提供的调试环境那样的调试环境,或者是否有其他方法可以以开发者模式运行浏览器并在控制台中查看所有这些错误。为什么Firebug在页面运行时保持沉默,但在我在控制台中输入有问题的代码时显示错误(控制台始终打开)? - user58777
4个回答

7
我认为这个问题的一些答案误解了问题。如果我理解正确,问题是说当这段代码在一个真正的网页中运行时,错误确实被抑制了,但OP不希望它被抑制。(主要是为了调试目的)。
那么我的问题是,这段代码在网站的上下文中真正运行的位置在哪里?很有可能在错误到达你之前,其他东西已经抑制了它。例如,一些库可能本能地抑制在特定回调中发生的错误 (例如 XHR)。然而,如果它们做得好,它们也倾向于提供一个钩子点来接收通知,以便知道是否发生了错误。

1
你说得对。既然你提到了,我想我有时候看到YUI(YUI 2.8)捕获错误。也许他们在很多代码中运行try catch块?我将尝试在try catch块中运行我的代码,看看会发生什么。 - user58777
简单的回调函数(例如表单输入)会欣然接受异常而不留痕迹。我实际上在很多地方都有防御性的try catch,以确保错误会被记录。除非我也在处理程序中放置一个try catch,否则这些都似乎无法捕获处理程序异常。任何假设回调是无误的地方都是设计上的问题。像JavaScript这样的动态语言可能会发生错误。简单的引用或类型错误或未定义错误经常发生。如果浏览器始终记录未捕获的异常,那将是很棒的。 - Jilles van Gurp
这是非常正确的。经过多个月后,我才意识到这正是我的错误没有在Firefox控制台中弹出的确切原因。在WebExtension开发的背景下,看起来'browser.tabs.sendMessage'甚至可以捕获内容脚本中的异常。谢谢! - neurosock

6
下面的代码将在catch块中捕获所有错误:
var a;
try {
    a = new Foo.Apple();
} catch (err) {
    // Error handling
}

了解更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch

这个链接提供了有关 JavaScript 中 "try...catch" 语句的详细信息。它允许您编写错误处理代码块,以便在代码发生错误时执行某些操作,而不会使整个程序崩溃。

1
在块内声明变量的做法是错误的。变量声明语句应该是执行上下文的第一条语句。在程序“中间”声明变量是一种不好的编程习惯。 - Šime Vidas
1
关于变量声明,你是正确的,在注释中进行了修正。关于存在性检查,如果你需要具体知道哪个声明失败了,你是正确的,但在不重要和有许多检查的情况下,我认为这种方式更好。 - matte
1
谢谢。我的观点是,如果你不需要知道哪一个失败了(如果你调用多个构造函数),那么所有的if/else块都是没有必要的,它们只会使源代码混乱。 - matte
当然你想知道哪个构造函数失败了!因为你需要那个构造函数,也就是它的功能。逻辑如下:1. 你需要某个构造函数来完成某些功能。2. 你检查该构造函数是否存在。如果存在,你使用它。如果不存在,你运行一些替代代码,其中a)创建这样的构造函数或b)以其他方式实现相同的功能。这是为了确保“工作得到完成”。这就是为什么我们使用if-else的原因。 - Šime Vidas
在您的解决方案中,如果构造函数不存在,您只需"调用整个操作"。在catch块中,您无法修复该问题。 - Šime Vidas
显示剩余5条评论

4

如果您正在处理那些在运行时不确定是否存在的对象,您需要检查它们是否存在:

if (Foo && Foo.Apple) {
    // exists, do something with it
} else {
    // doesn't exist, do Plan B
}

请注意,表达式(Foo && Foo.Apple)将首先检查Foo是否存在,只有当它存在时,才会检查其是否具有名为Apple的属性。如果有,则执行if分支。
如果Foo不存在,或者它不包含Apple属性,则执行else分支。

你说得没错,但这个问题是因为我的JavaScript“bundle”中有一个组件没有加载。代码并不希望该组件不存在,它是一个依赖项。我的问题更多的是如何找到一种方法来获得通知,而不是一个令人沮丧的静默错误。 - user58777
如果你有多个组件,你必须采取防御姿态,并考虑到一个组件可能无法加载/执行的可能性。当然,你期望它在那里,但你不能确定。这就是为什么你要进行防御性编程,并始终首先使用if语句检查特定组件是否存在。如果存在,那就好,如果不存在,使用else分支作为“通知”。当然,你可以利用else分支尝试重新加载组件(例如)。 - Šime Vidas

3

同意@sime Vidas的观点,如果必须处理异常而不是保持静默,请首先使用布尔条件并检查值是否存在。

if(Foo.Apple){
\\your code
}
else
{
//Foo.Apple does not exist, do some exception handling here
}

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