Отладка Javascript

Posted by Hades on 27 Ноябрь 2009 in Новости |

Отладка JavaScriptJavascript вывалил ошибку? Замечательно! Нет, это конечно плохо, но гораздо лучше, чем если бы он промолчал (да, бывает и такое!) в случае ошибки. Для этого рассмотрим средства Javascript Debug’а в основных браузерах.

Debuggers

Вот основные браузеры и их средства отладки:

  • firefoxFirefox: Всеми нами любимый плагин Firebug
  • safari Safarigooglechrome Chrome: Встроенный в WebKit Web Inspector
  • opera Opera: Чудесный встроенный Dragonfly
  • ie Internet Explorer 8: Встроенный Developer Tools
  • ie Internet Explorer <= 7 : Тут есть множество вариантов: DebugBar, Companion.JS, через MS Visual Studio
    Все они либо громоздкие, либо неудобные, либо платные :) Есть хороший script Debugger. Он очень спартанский, но в нём есть всё, что мне нужно.

Во всех этих средствах отладки нас будут интересовать breakpoint’ы:

breakpointА вот немного «вкусностей» — conditional breakpoints (правый клик по «бряке»):

breakpointconditional

То есть заводим глобальную переменную (к примеру) allowBreakpoints и «бряки» будут срабатывать только тогда, когда мы сами того захотим.
К сожалению, работает не везде.

Как «тормознуть» поток

Ключевое слово debugger. Увидав такое в коде, любой уважающий себя JS-debugger остановит поток Javascript и покажет нам место остановки

scr8Можно смело пользоваться в:

  • firefoxFirefox: Firefox со включенным Firebug’ом
  • safari Safarigooglechrome Chrome: с открытым/включённым Web Inspector/script Panel
  • opera Opera: с открытым/включённым Dragonfly
  • ie Internet Explorer 8: с открытым/включённым Developer Tools
  • ie Internet Explorer <= 7: с установленным script Debugger

И не бойтесь писать debugger в вашем коде — ошибки это нигде не вызовет.

А вот вариант с условной остановкой:

if (allowBreakpoints == true)
debugger;

Мне так нравится гораздо больше, чем ставить «бряку»: так я пишу код и дебажу его по сути в одном месте, а не в двух.

Debug через alert()

Это наименее информативный debug, который к тому же останавливает поток Javascript. Да к тому же модальный по отношению к браузеру. Забудьте, что он вообще существует.

Особенность breakpoint’ов

Рассмотренные варианты все, как один, тормозят поток Javascript. Это плохо!

Почему? Если в момент остановки скрипта у вас был запущен AJAX-запрос или Timeout, и ответ не успел вернутся — он может уже не вернутся никогда. Согласитесь, в современных web-проектах этого добра хватает. Поэтому в момент «экстренной остановки» скрипта мы уже не сможем адекватно debug’ать дальше — часть логики будет безвозвратно утеряна.

Поэтому я стараюсь избегать на практике debug с остановкой.

Однако: breakpoint есть breakpoint, и если вы исследуете ну очень запущенный баг — тут без остановки не обойтись (надо будет сделать watch текущим переменным и т.д.)

«Правильный» debug

Коротко: хороший debug — через logging. Так я в основном и работаю — в нужном месте в нужное время срабатывает console.log(…).

Да, насчёт console.log — впервые этот метод увидел мир, насколько я помню, вместе с Firebug. Никакой это не стандарт и не факт, что оно заработает в IE6. Однако современные браузеры вводят logging именно как console.log. Это так, к сведению. И если в продакшн попадёт код с console.log(…) — будьте на чеку, может поломаться! Так что может быть стоит переопределить у себя в коде объект console, так, на всякий пожарный.

Если же в целевом браузере нет console.log, а хочется — попробуйте Firebug Lite или Blackbird, может понравится ;)

Пример №1

Javascript показал ошибку. Надо понять — что к чему.
Включаем в debugger’е режим «Break On Error»:

stoponerror

Воспроизводим ошибку снова. Javascript останавливается. Видим место ошибки, делаем watch и точно определяем, в чём же дело.

Пример №2

CASE:
Javascript не показал ошибку. Но вы знаете, что она есть (как суслик). Да, такое иногда бывает.

CASE:
Надо просто продебажить некий код. Скажем, посмотреть, что происходит по нажатию кнопки или после AJAX-загрузки данных.

Тут сложней — надо найти, с чего начать.

Немного искусства

Поиск «точки входа» Javascript’а — непростая штука. Вот как я это делаю:

  1. Самое главное — разбираться в средстве разработки. Будь то jQuery, или ExtJS, или Mootools, или вообще свой собственный framework — нужно понимать, как создаётся кнопка, как «навешивается» обработчик события, как данные ходят в AJAX, как попадают в grid, как работает TinyMCE RTE, как, как, как… Если нет понимания задачи — не получится её решить!
  2. Используем Inspect нашего debugger’а (если нет Inspect’а — используйте всё тот же Firebug Lite):
    1. Находим нужный элемент HTML (например, кнопку)
    2. Ищем ближайший от него элемент с осмысленным ID (н-р: id=«my-super-button»; а id=«ext-gen124» уже не подходит) вверх по иерархии (это может быть и сама кнопка, а может быть DIV четырмя уровнями выше)
  3. Ищём в нашем коде вхождение этого осмысленного ID’шника
  4. Нашли. Отлично, теперь вдумчиво читаем код и находим нужное место (обработчик нажатия кнопки, AJAX-запрос и т.д.)
  5. Пишем в нужном месте debugger:

    // условная остановка
    if (allowBreakpoints == true)
    debugger;

    // или просто
    debugger;

Конечно данный способ не идеален. Бывает, что даёт промашки. Но это хороший способ, мне он сильно помагает в работе.

Так, значит место в коде нашли, бряку поставили. Если не хочется (или просто нельзя) изменять исходный код — можно вместо ключевого слова debugger поставить brakepoint в средстве отладки.

Пример №3

Тот же случай: надо продебажить некий код. Скажем, посмотреть, что происходит по нажатию кнопки или после AJAX-загрузки данных. Но в этот раз мы не можем тормозить поток Javascript по описанным мной причинам.

Итак:

  1. Ищем нужное место тем же способом
  2. Вместо debugger пишем console.log(variable_to_watch)

Тут есть интересные модернизации.

CASE UNO

variable_to_watch — объект, который изменился с момента вывода в консоль. А хочется увидить его состояние именно на момент вызова.

Тут надо использовать не console.log(variable_to_watch), а console.dir(variable_to_watch)

CASE DUO

Нужно не просто увидеть текущее значение variable_to_watch, но ещё и поэкспериментировать с ним (например, хочется вызвать его метод):

// пусть хочется получить доступ к объекту obj
if (debugEnabled)
console.log(window.temp_var = obj);

Таким образом мы не только увидим вывод в консоли, но и получим доступ к объекту через глобальную ссылку на него: window.temp_var.

Открываем Firebug->Console и вызваем метод: temp_var.objMethod().

Нет консоли? Пишем в адресной строке: javascript:alert(temp_var.objMethod()); void 0;

Пример №4

Ещё один пример. Возможно, немного странный. Хочется продебажить метод 3d-party-framework’а (например, ExtJS), но вот беда — нельзя тормозить Javascript и нет доступа к исходному коду (правда странный пример? :)

Что же делать? Я делаю так:

Создаём файл с патчем: my-ext-patch.js, и подключаем его после ext-all.js
Внутри пишем что-то вроде:

(function() {
var _backup = Ext.form.Form.render; // Резервируем метод рендера формы. — Ваш Кэп ;)

Ext.form.Form.render = function(container) { // Wrap’им метод
// А вот и дебаг
console.log(container);

// Возможны варианты:
// console.dir(container);
// console.log(window.t = container);
// debugger;

// Выполняем начальный метод
return _backup.apply(this, arguments);
}
})();

Случайные статьи:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Security Code:

Copyright © 2008-2012 C миру по нитке… All rights reserved.
Desk Mess Mirrored version 1.9.1 theme from BuyNowShop.com.