Подтвердить что ты не робот

Стек вызовов теряется, если исключение выбрано в обработчике jQuery

У меня проблема с отладкой моих веб-приложений. Это очень разочаровывает, потому что я пытаюсь воспроизвести проблему с небольшой веб-страницей, которую я могу опубликовать на jsfiddle, но это похоже на случай с "Хиггсом-Бугсоном".

У меня есть веб-страница с большим обработчиком 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 поймает ошибку и выделит строку кода, в которой произошла ошибка, и отобразит стек вызовов, включая factorial и btnFactorial_click.

Этот код также вызывает factorial(-1) из обработчика $(document).ready. В этом случае Visual Studio перемещает выделение в блок finally в следующем коде jQuery (вырванный из 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?

4b9b3361

Ответ 1

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/

При запуске jsfiddle в chrome вызывается первый запуск через factorial (-1). Появится сообщение об ошибке. Доступ к нему можно получить, щелкнув в правом нижнем углу на красном x или проверив элемент, перейдя на вкладку консоли, а затем просмотрев текстовую область. Ошибка корректно читает сообщение "Неиспользуемая ошибка: факториальная функция не поддерживает отрицательные числа", со ссылкой на точную строку, где используется throw new Error().

Возможно, мне нужно немного больше разъяснений, в чем проблема, которую вы пытаетесь решить? Кажется, что chrome отлаживает этот script просто отлично. Возможно, есть некоторые проблемы с отладчиком 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

Ответ 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. Все остальное должно быть загружено в память, пока страница все еще отображается.

Ответ 3

Я попробовал ваш небольшой пример со встроенным отладчиком IE и сообщил сообщение об исключении просто отлично, поместив курсор в бросок.

То же самое в Chrome.

У меня есть jquery v1.6.2. Может стоить обновление?

И снова это пахнет проблемой потоковой передачи. Если это всегда происходит в сочетании с обновлением пользовательского интерфейса (например, предупреждение), это может быть отладчик VS смотрит на поток сервера пользовательского интерфейса, когда он думает об этом в потоке js. Другими словами, ошибка в отладчике. Если это так, вы должны попробовать другой отладчик, чтобы увидеть, исчезает ли проблема.