简体   繁体   English

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

[英]Call stack is lost when an exception is thrown within a jQuery handler

I'm having a problem debugging my web applications. 我在调试我的Web应用程序时遇到问题。 It's very frustrating because I've been trying to reproduce the problem with a small web page that I can post on jsfiddle, but this seems to be a case of the "Higgs-Bugson". 这是非常令人沮丧的,因为我一直试图通过一个小网页重现问题,我可以在jsfiddle上发布,但这似乎是“希格斯 - 布格森”的情况。

I have a web page with a large jQuery(document).ready() handler. 我有一个带有大型jQuery(document).ready()处理程序的网页。 The problem is that when an exception is thrown from within the jQuery(document).ready() handler, I get a call-stack with several anonymous functions and no pointer to the code that actually threw the exception. 问题是当从jQuery(document).ready()处理程序中抛出异常时,我得到一个带有几个匿名函数的调用堆栈,并且没有指向实际抛出异常的代码的指针。

Whenever I try to reproduce this behavior with a small web page, I always get a pointer to the code that threw the exception, but in production code, I never get the stack pointer. 每当我尝试用一​​个小网页重现这种行为时,我总是得到一个指向抛出异常的代码的指针,但在生产代码中,我从来没有得到堆栈指针。 This makes debugging more frustrating and error-prone. 这使得调试更令人沮丧且容易出错。

Does anyone here any any idea what could be causing this behavior and how to make it right? 有没有人知道什么可能导致这种行为以及如何使它正确?


Update: It's been several months since I posted this question and I now believe that I have conclusively reproduced the issue. 更新:我发布这个问题已有几个月了,我现在相信我已经最终重现了这个问题。 I reproduce the issue with the following HTML: 我用以下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>

Looking at the code, you'll see that when you click a button, the code alerts the factorial of a number that you specify. 查看代码,您会看到当您单击按钮时,代码会警告您指定的数字的阶乘。 Enter a negative number and an error will be produced. 输入负数,将产生错误。 In this case, Visual Studio will catch the error and highlight the line of code where the error occurred and display a call stack including factorial and btnFactorial_click . 在这种情况下,Visual Studio将捕获错误并突出显示发生错误的代码行,并显示包含factorialbtnFactorial_click的调用堆栈。

This code also invokes factorial(-1) from the $(document).ready handler. 此代码还从$(document).ready处理程序调用factorial(-1) In this case, Visual Studio moves the highlight to the finally block in the following jQuery code (excerpted from jquery-1.6.1.js, beginning on line 987 在这种情况下,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;
            },

Although the call stack is not displayed, Visual Studio displays a pop-up showing the text of the error. 虽然未显示调用堆栈,但Visual Studio会显示一个弹出窗口,显示错误的文本。

What is the reason for this odd behavior and how can I design my application so that I can easily trap errors that originate from handlers such as $(document).ready? 这种奇怪的行为是什么原因,我如何设计我的应用程序,以便我可以轻松捕获源自处理程序的错误,如$(document).ready?

I'm having a problem debugging my web applications

What type of debugger are you using? 你使用什么类型的调试器? They tend to vary and the best one that I have found when developing is firefox's because of some very nice integrated tools they have. 它们往往是变化的,我在开发时发现的最好的是firefox,因为它们有一些非常好的集成工具。

Although it is nice to reproduce a problem, when it cannot be reproduced in a simple succinct example then debugging becomes more and more important. 尽管重现问题很好,但是当它无法在简单的简洁示例中再现时,调试变得越来越重要。 Setting breakpoints and going line by line is sometimes the only way instead of waiting for the error to occur during runtime and then tracing back. 设置断点并逐行进行有时是唯一的方法,而不是等待在运行时期间发生错误然后追溯。

There are several approaches outlined in this MSDN article which could be useful to helping solve your problem. 本MSDN文章中概述了几种方法,可以帮助您解决问题。 I am sure you have tried some of them, but it is at least worth looking at - notably "Scenario 3: I am getting an error deep inside a set of helper methods, and I'm not sure where the error originated." 我相信你已经尝试了其中的一些,但它至少值得关注 - 特别是“场景3:我在一组辅助方法内部得到了一个错误,而且我不确定错误源自何处。”

"How to Debug Your jQuery Code" “如何调试jQuery代码”

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

Edit in response to new content 编辑以响应新内容

jsfiddle of new content: http://jsfiddle.net/EJbsS/ jsfiddle的新内容: http//jsfiddle.net/EJbsS/

When running the jsfiddle in chrome, the first run through factorial(-1) is called. 在chrome中运行jsfiddle时,会调用第一次运行factorial(-1)。 An error appears. 出现错误。 It can be accessed by clicking in the bottom right at the red x, or by inspecting element, navigating to the console tab, and then looking at the text area. 可以通过单击红色x右下角,或通过检查元素,导航到控制台选项卡,然后查看文本区域来访问它。 The error properly reads "Uncaught Error: factorial function doesn't support negative numbers ", with a link to the exact line where throw new Error() is used. 错误正确读取“Uncaught Error:factorial function不支持负数”,并带有指向使用throw new Error()的确切行的链接。

Perhaps I need a little more clarification, what is the issue that you are trying to resolve? 也许我需要更多澄清一下,你要解决的问题是什么? It seems that chrome debugs this script just fine. 似乎chrome调试这个脚本就好了。 Perhaps there are some issues with Visual Studio's debugger. 也许Visual Studio的调试器存在一些问题。

Moreover 此外

Here is a reproduction of a working page that can be used from notepad saved as .html 这是一个工作页面的复制品,可以从保存为.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>

When running this page in google chrome, navigating to the sources tab, and setting a breakpoint at Line 26: if (x < 0) the entire call stack is reproduced when the page is run, on the right hand side. 在谷歌浏览器中运行此页面时,导航到“源”选项卡,并在Line 26: if (x < 0)设置断点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)

Even further 更深入

Hopefully this caveat will be the best yet. 希望这个警告将是最好的。 Looking a little into stack tracing, I found this: console.trace(); 看一下堆栈跟踪,我发现了这个: console.trace(); . It is very useful. 非常有用。

Insert it into the above code at line 26 like so: 将其插入第26行的上述代码中,如下所示:

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

Becomes

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

Running it now, without a breakpoint, will produce the stack trace in the console when the error condition is met: 现在运行它, 没有断点,将在满足错误条件时在控制台中生成堆栈跟踪:

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

I would suggest creating an object which is instantiated within the jQuery(document).ready() block. 我建议创建一个在jQuery(document).ready()块中实例化的对象。 For example: 例如:

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

oStart.init();

This will help you separate your application logic and the jQuery only logic. 这将帮助您分离应用程序逻辑和仅jQuery逻辑。 You should have very little in your ready block. 你准备好的块应该很少。 Only those things which are absolutely necessary after the DOM has loaded completely. 只有那些在DOM完全加载后绝对必要的东西。 Everything else should be able to be loaded into memory while the page is still rendering. 在页面仍在渲染时,其他所有内容都应该能够加载到内存中。

I tried your small example with the built-in IE debugger and it reported the exception message just fine, placing the cursor on the throw. 我用内置的IE调试器尝试了你的小例子,它报告了异常消息就好了,把光标放在了throw上。

The same in Chrome. 在Chrome中也一样。

I have jquery v1.6.2. 我有jquery v1.6.2。 Maybe worth an upgrade? 也许值得升级?

Then again, this smells like a threading issue. 然后再次,这闻起来像一个线程问题。 If it always happens in conjunction with a UI update (like the alert), it could be the VS debugger is looking at a UI server thread when it thinks it's in the js thread. 如果它总是与UI更新(如警报)一起发生,则可能是VS调试器在认为它位于js线程中时正在查看UI服务器线程。 In other words, a bug in the debugger. 换句话说,调试器中的错误。 If this is the case, you should try a different debugger to see if the problem disappears. 如果是这种情况,您应该尝试使用其他调试器来查看问题是否消失。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM