12

我在调试 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

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

            // resolve with given context and args
            resolveWith: function( context, args ) {
                if ( !cancelled && !fired && !firing ) {
                    // make sure args are available (#8421)
                    args = args || [];
                    firing = 1;
                    try {
                        while( callbacks[ 0 ] ) {
                            callbacks.shift().apply( context, args );
                        }
                    }
                    finally {
                        fired = [ context, args ];
                        firing = 0;
                    }
                }
                return this;
            },

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

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

4

3 回答 3

4

I'm having a problem debugging my web applications

您使用的是什么类型的调试器?它们往往会有所不同,我在开发时发现最好的一个是 Firefox,因为它们拥有一些非常好的集成工具。

虽然重现一个问题很好,但是当它不能在一个简单简洁的例子中重现时,调试就变得越来越重要。设置断点并逐行执行有时是唯一的方法,而不是在运行时等待错误发生然后回溯。

这篇 MSDN 文章中概述了几种方法,它们可能有助于解决您的问题。我相信您已经尝试过其中的一些,但至少值得一看 - 特别是“场景 3:我在一组辅助方法的深处遇到了错误,我不确定错误的来源。”

“如何调试你的 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>

在 google chrome 中运行此页面时,导航到源选项卡并在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
于 2012-06-14T17:42:51.757 回答
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 完全加载后绝对必要的东西。当页面仍在渲染时,其他所有内容都应该能够加载到内存中。

于 2012-05-14T20:52:42.870 回答
1

我用内置的 IE 调试器尝试了你的小例子,它很好地报告了异常消息,将光标放在 throw 上。

在 Chrome 中也是如此。

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

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

于 2012-08-10T04:35:26.377 回答