在jQuery处理程序中抛出异常时,调用堆栈将丢失

时间:2012-05-08 14:53:38

标签: jquery debugging exception exception-handling callstack

我在调试Web应用程序时遇到问题。这是非常令人沮丧的,因为我一直试图通过一个小网页重现问题,我可以在jsfiddle上发布,但这似乎是“Higgs-Bugson”的情况。

我有一个带有大jQuery(document).ready()处理程序的网页。问题是当从jQuery(document).ready()处理程序中抛出异常时,我得到一个带有几个匿名函数的调用堆栈,并且没有指向实际抛出异常的代码的指针。

每当我尝试使用小网页重现此行为时,我总是获取指向抛出异常的代码的指针,但在生产代码中,我从不得到堆栈指针。这使得调试更令人沮丧且容易出错。

有没有人知道可能导致此行为的原因以及如何使其正确?


更新:我发布这个问题已有几个月了,我现在相信我已经最终转载了这个问题。我用以下HTML重现了这个问题:

<html xmlns="http://www.w3.org/1999/xhtml" >    
<body>
Factorial Page
<input type='button' value='Factorial' id='btnFactorial' />
<script src="Scripts/jquery-1.6.1.js" type="text/javascript"></script>
<script type='text/javascript'>
    $(document).ready(documentReady);

    function documentReady() {
        $('#btnFactorial').click(btnFactorial_click);

        factorial(-1);
    }

    function btnFactorial_click() {
        var x;
        x = prompt('Enter a number to compute factorial for.', '');
        alert(x + '! = ' + factorial(x));
    }

    function factorial(x) {
        if (x < 0)
            throw new Error('factorial function doesn\'t support negative numbers');
        else if (x === 0 || x === 1)
            return 1;
        else
            return factorial(x - 1) * x;
    }
</script>       
</body>
</html>

查看代码,您会看到当您单击按钮时,代码会警告您指定的数字的阶乘。输入负数,将产生错误。在这种情况下,Visual Studio将捕获错误并突出显示发生错误的代码行,并显示包含factorialbtnFactorial_click的调用堆栈。

此代码还从$(document).ready处理程序调用{​​{1}}。在这种情况下,Visual Studio将突出显示移动到以下jQuery代码中的finally块(摘自jquery-1.6.1.js,从第987行开始

factorial(-1)

虽然未显示调用堆栈,但Visual Studio会显示一个弹出窗口,显示错误文本。

这种奇怪的行为是什么原因以及如何设计我的应用程序以便我可以轻松捕获源自处理程序的错误,例如$(document).ready?

3 个答案:

答案 0 :(得分:4)

I'm having a problem debugging my web applications

您使用的调试器类型是什么?它们往往是变化的,我在开发时发现的最好的是firefox,因为它们有一些非常好的集成工具。

尽管重现问题很好,但是当它无法在简单的简洁示例中再现时,调试变得越来越重要。设置断点并逐行进行有时是唯一的方法,而不是在运行时等待错误发生,然后追溯。

本MSDN文章中概述了几种可能有助于解决问题的方法。我相信你已经尝试了其中的一些,但它至少值得一看 - 特别是“场景3:我在一组辅助方法中得到了一个错误,而且我不确定错误源自何处。” / p>

“如何调试jQuery代码”

http://msdn.microsoft.com/en-us/magazine/ee819093.aspx

编辑以响应新内容

新内容的jsfiddle:http://jsfiddle.net/EJbsS/

在chrome中运行jsfiddle时,会调用第一次运行factorial(-1)。出现错误。可以通过单击红色x右下角,或通过检查元素,导航到控制台选项卡,然后查看文本区域来访问它。错误正确显示“未捕获的错误:因子函数不支持负数”,并带有指向使用throw new Error()的确切行的链接。

也许我需要更多澄清一下,您要解决的问题是什么?似乎chrome调试这个脚本就好了。也许Visual Studio的调试器存在一些问题。

<强>此外

以下是可以在保存为.html

的记事本中使用的工作页面的复制品
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>demo</title> 
<script type='text/javascript' src='http://code.jquery.com/jquery-1.6.4.js'></script>
<script type='text/javascript'>//<![CDATA[ 
$(window).load(function(){
$(document).ready(documentReady);
function documentReady() {
    $('#btnFactorial').click(btnFactorial_click);

    factorial(-1);
}

function btnFactorial_click() {
    var x;
    x = prompt('Enter a number to compute factorial for.', '');
    alert(x + '! = ' + factorial(x));
}

function factorial(x) {
    if (x < 0)
        throw new Error('factorial function doesn\'t support negative numbers');
    else if (x === 0 || x === 1)
        return 1;
    else
        return factorial(x - 1) * x;
}
});//]]>  
</script>
</head>
<body>
Factorial Page
<input type='button' value='Factorial' id='btnFactorial' />  
</body>
</html>

在谷歌浏览器中运行此页面时,导航到“源”选项卡,并在Line 26: if (x < 0)设置断点,在页面运行时,将在右侧再现整个调用堆栈。

factorial (debugpage.html:26)
documentReady (debugpage.html:16)
jQuery.extend._Deferred.deferred.resolveWith (jquery-1.6.4.js:1016)
jQuery.extend._Deferred.deferred.done (jquery-1.6.4.js:1002)
jQuery.fn.jQuery.ready (jquery-1.6.4.js:282)
(anonymous function) (debugpage.html:11)
jQuery.event.handle (jquery-1.6.4.js:3001)
jQuery.event.add.elemData.handle.eventHandle (jquery-1.6.4.js:2635)

更进一步

希望这个警告将是最好的。看一下堆栈跟踪,我发现了这个:console.trace();非常有用。

将其插入第26行的上述代码,如下所示:

if (x < 0)
    throw new Error('factorial function doesn\'t support negative numbers');
else if (x === 0 || x === 1)

变为

if (x < 0){
    console.trace();
    throw new Error('factorial function doesn\'t support negative numbers');
}else if (x === 0 || x === 1)

现在运行它,没有断点,将在满足错误条件时在控制台中生成堆栈跟踪:

console.trace() debugpage.html:27
factorial debugpage.html:27
documentReady debugpage.html:16
jQuery.extend._Deferred.deferred.resolveWith jquery-1.6.4.js:1016
jQuery.extend._Deferred.deferred.done jquery-1.6.4.js:1002
jQuery.fn.jQuery.ready jquery-1.6.4.js:282
(anonymous function) debugpage.html:11
jQuery.event.handle jquery-1.6.4.js:3001
jQuery.event.add.elemData.handle.eventHandle

答案 1 :(得分:2)

我建议创建一个在jQuery(document).ready()块中实例化的对象。例如:

var oStart = function(){
    var pageMethod = function(){ /*...*/ }
    var pageMethodOther = function(){ /*...*/ }
    /*...*/
    var init = function(){
        jQuery(document).ready(function(){
            /* do your stuff here */
        });
    }
}

oStart.init();

这将帮助您分离应用程序逻辑和仅jQuery逻辑。你准备好的块应该很少。只有那些在DOM完全加载后绝对必要的东西。在页面仍在渲染时,其他所有内容都应该能够加载到内存中。

答案 2 :(得分:1)

我尝试使用内置IE调试器的小例子,它报告了异常消息,将光标放在了抛出上。

在Chrome中也一样。

我有jquery v1.6.2。也许值得升级?

然后再次,这就像一个线程问题。如果它总是与UI更新(如警报)一起发生,则可能是VS调试器在认为它位于js线程中时正在查看UI服务器线程。换句话说,调试器中的错误。如果是这种情况,您应该尝试使用其他调试器来查看问题是否消失。