Дружеский совет: эта статья содержит множество демонстрационных GIF-анимаций. На мобильном устройстве старайтесь читать в среде Wi-Fi.


Предисловие: навыки отладки — это незаменимый навык в любых технологических исследованиях и разработке. Овладение различными техниками отладки непременно позволит добиваться вдвое лучшего результата при вдвое меньших усилиях. Например, быстро находить проблемы, снижать вероятность сбоев, помогать анализировать логические ошибки и так далее. Сегодня, когда фронтенд-разработка в Интернете становится всё более важной, вопрос о том, как снизить затраты на разработку и повысить эффективность работы во фронтенд-разработке, делает особенно важным овладение навыками отладки фронтенд-разработки.


В этой статье будут по очереди объяснены различные методы отладки JS во фронтенде. Возможно, вы уже хорошо ими владеете — давайте вместе их повторим. Возможно, есть методы, которых вы не видели, — почему бы не изучить их вместе. Возможно, вы ещё не знаете, как отлаживать, — воспользуйтесь этой возможностью, чтобы восполнить пробел.


1. Мастер отладки уровня ветерана: Alert


Это была эпоха, когда Интернет только зарождался. Фронтенд-веб-страницы в основном использовались для отображения контента, а браузерные скрипты могли предоставлять страницам лишь очень простые вспомогательные функции. В то время веб-страницы в основном работали в браузерах, где доминировал IE6, а возможности отладки JS были очень слабыми. Отладку можно было выполнять только с помощью метода alert, встроенного в объект Window. Тогда это, вероятно, выглядело так:


1465008820-3618-DRwtoQT7voibhRD94QpmhvtYwQLA


Следует отметить, что эффект, показанный здесь, — это не то, что видели в браузерах IE в те времена, а эффект в более высокой версии IE. Кроме того, тогда, похоже, не было такой продвинутой консоли, и alert использовался в реальном JS-коде страницы. Хотя метод отладки с помощью alert примитивен, в то время он действительно имел неизгладимую ценность, и даже сегодня он всё ещё занимает своё место.


2. Король отладки нового поколения: Console


Поскольку JS умеет всё больше в веб-фронтенде, его обязанности растут, а роль становится всё важнее. Традиционный метод отладки через alert постепенно перестал соответствовать различным сценариям фронтенд-разработки. К тому же отладочная информация, всплывающая в alert, отображается в довольно непривлекательном окне и перекрывает часть содержимого страницы, что делает его не слишком удобным.


С другой стороны, отладочные сообщения через alert требуют добавления в логику программы выражений вроде "alert(xxxxx)", чтобы работать нормально, а alert также блокирует дальнейшую отрисовку страницы. Это означает, что после отладки разработчикам приходится вручную удалять этот отладочный код, что довольно хлопотно.


Поэтому новое поколение браузеров, включая Firefox, Chrome и IE, последовательно выпустило консоли отладки JS, поддерживающие формы вроде "console.log(xxxx)" для вывода отладочной информации в консоль без прямого влияния на отображение страницы. На примере IE это выглядит так:


1465008820-2300-ogTqaJgtj02s0OsyJWuITpka96AQ


Что ж, прощай, уродливое всплывающее окно alert. А восходящие звёзды во главе с браузером Chrome сделали функциональность Console ещё богаче:


1465008820-6145-QTgB1GX5RGfA3PgOMibcloakZXIQ


Думаете, этого достаточно? Воображение команды разработчиков Chrome поистине восхищает:


1465008820-2158-uon7Hnaqk8rpSAAjCvmqibvribTA


Ладно, я немного отвлёкся. Короче говоря, появление консоли и встроенного в браузер объекта Console принесло огромное удобство для отладки фронтенд-разработки.


Некоторые могут спросить: разве такой отладочный код тоже не нужно убирать после отладки?


Что касается этого вопроса, если сначала выполнить проверку существования перед использованием объекта console, то если его не удалить, это не нарушит бизнес-логику. Конечно, ради чистоты кода после отладки всё же следует по возможности удалить этот отладочный код, не связанный с бизнес-логикой.


3. Отладка точек останова в JS


Точка останова: одна из функций отладчика, она может прервать программу в нужном месте, что удобно для анализа. Вы также можете задать точки останова в одном сеансе отладки, а в следующий раз просто позволить программе автоматически дойти до заданной точки останова, где она остановится на ранее установленной точке останова. Это значительно упрощает работу и экономит время. — Baidu Baike

Отладка с точками останова в JS означает добавление точек останова в код JS в инструментах разработчика браузера, чтобы выполнение JS останавливалось в определённой позиции, что удобно для разработчиков при анализе фрагмента кода и обработке логики. Чтобы наблюдать эффект от отладки с точками останова, мы заранее подготовили фрагмент кода JS:


1465008820-8904-dpkouCeucc7IXxBjtRNwQswHiakA


Код очень простой: определяется функция, в неё передаются два числа, к каждому прибавляется случайное целое число, а затем возвращается сумма этих двух чисел. На примере инструментов разработчика Chrome рассмотрим основной способ отладки JS с точками останова.


3.1. Точка останова в Sources


Сначала по выводу в консоли на рисунке выше мы видим, что тестовый код должен был выполниться нормально. Но почему «должен»? Потому что в функцию добавляется случайное число. Действительно ли итоговый результат верен? Это бессмысленное предположение, но допустим, я теперь хочу проверить: два числа, переданные в функцию, добавленные случайные числа и итоговую сумму. Так как же это сделать?


Способ 1, самый обычный, упомянутый ранее: используя alert или console, мы можем проверить это так:


1465008820-8340-mHoUQU3TkcAOP8xLnYk2NhcUialw


На рисунке выше мы добавили три строки кода с console, чтобы вывести интересующие нас переменные данных. Наконец, по выводу в консоли (панель Console) мы можем ясно проверить, нормально ли проходит весь процесс вычисления, тем самым выполнив требования проверки из постановки нашей задачи.


Способ 2: очевидный недостаток Способа 1 в том, что он добавляет много избыточного кода. Далее давайте посмотрим, удобнее ли использовать точки останова для проверки. Сначала рассмотрим, как добавить точку останова и каков эффект после остановки:


1465008820-9543-cLX7KYiaaTVXstsgZjALFNgxVmIQ


Как показано на рисунке, процесс добавления точки останова к фрагменту кода таков: «F12 (Ctrl + Shift + I) открыть инструменты разработчика» → «щелкнуть меню Sources» → «найти соответствующий файл в дереве слева» → «щелкнуть по столбцу с номерами строк», чтобы завершить добавление/удаление точки останова на текущей строке. После добавления точки останова обновите страницу, и выполнение JS остановится на точке останова. В интерфейсе Sources вы увидите все переменные и значения в текущей области видимости. Просто проверьте каждое значение, чтобы выполнить требования к проверке из условия нашей задачи.


Теперь возникает проблема: внимательные читатели заметят, что когда код доходит до точки останова, отображаемые значения переменных a и b уже прошли сложение, и мы не можем увидеть исходные 10 и 20, переданные при вызове функции sum. Что же делать? Нужно вернуться и сначала изучить основы отладки с точками останова. После открытия панели Sources мы фактически увидим следующее содержимое. Давайте проследим за курсором мыши и посмотрим, что означает каждая часть:


1465008821-7994-vY1kp4mXibRLhG16q7ENiaqld26w


Слева направо функции, обозначаемые каждой иконкой, таковы:

  • Pause/Resume script execution: приостановить/возобновить выполнение скрипта (программа останавливается при достижении следующей точки останова).
  • Step over next function call: выполнить вызов функции на следующем шаге (перейти на следующую строку).
  • Step into next function call: войти в текущую функцию.
  • Step out of current function: выйти из текущей выполняемой функции.
  • Deactivate/Activate all breakpoints: отключить/включить все точки останова (не удаляя их).
  • Pause on exceptions: автоматически устанавливать точку останова на исключениях.

На данном этапе функциональные клавиши отладки по точкам останова в основном рассмотрены. Далее мы можем пройти по коду нашей программы строка за строкой и посмотреть, как изменяется каждая переменная после выполнения каждой строки, как показано на рисунке ниже:


1465008821-6404-WTpgjxsA6yNVYBdR5mX4WDXkhj0g


Как и выше, мы можем увидеть весь процесс для переменных a и b: от их начальных значений до добавления случайных значений по ходу, вплоть до окончательного вычисления суммы и вывода итогового результата. Выполнить требования проверки из условия задачи более чем легко.


Для оставшихся функциональных клавиш мы немного изменим наш тестовый код и с помощью GIF-изображения продемонстрируем их использование:


1465008820-1744-Lwm1Zm21Uzalicp2hfunoBux6KUA


Здесь нужно отметить одну вещь: возможность напрямую отображать значения переменных в области кода — это новая функция, добавленная в новых версиях Chrome. Если вы всё ещё используете старую версию Chrome, возможно, вы не сможете напрямую просматривать информацию о переменных в точке останова. В этом случае можно навести курсор мыши на имя переменной и ненадолго задержаться, чтобы увидеть значение переменной. Также можно выделить имя переменной мышью, щёлкнуть правой кнопкой и выбрать "Add to watch", чтобы просмотреть её на панели Watch. Этот способ также работает для выражений. Кроме того, находясь в точке останова, можно переключиться на панель Console, напрямую ввести имя переменной в консоли и нажать Enter, чтобы просмотреть информацию о переменной. Эта часть довольно простая. Учитывая длину статьи, я не буду приводить демонстрации с рисунками.


3.2. Точка останова Debugger


Так называемая точка останова Debugger — это на самом деле название, которое я придумал сам; не знаю профессионального термина. Конкретно, она означает добавление в код оператора "debugger;". Когда выполнение кода доходит до этого оператора, оно автоматически останавливается. Последующие операции почти в точности совпадают с добавлением точки останова на панели Sources, с той лишь разницей, что после отладки нужно удалить этот оператор.


Поскольку, помимо другого способа установки точки останова, её функция и эффект совпадают с добавлением точки останова на панели Sources, почему этот метод всё ещё существует? Думаю, причина такова: во время разработки мы иногда сталкиваемся с ситуациями, когда HTML-фрагменты (включая встроенный JS-код) загружаются асинхронно, и эту часть JS-кода нельзя найти в дереве Sources, поэтому мы не можем напрямую добавить точки останова в инструментах разработчика. Если мы хотим добавить точку останова в асинхронно загружаемые скрипты, в игру вступает "debugger;". Давайте посмотрим его эффект напрямую через GIF-изображение:


1465008821-1866-xQr5Nu4bh6h1njUeQaLRK1Cu6f1w


4. Отладка точек останова DOM


Точки останова DOM, как следует из названия, добавляют точки останова к DOM-элементам для достижения целей отладки. В реальном использовании эффект точек останова в конечном итоге оказывается внутри JS-логики. Давайте по очереди рассмотрим конкретный эффект каждого типа точек останова DOM.


4.1. Прерывание при изменении дочерних узлов внутри узла (Break on subtree modifications)


Поскольку фронтенд-разработка становится всё сложнее, фронтенд-JS-код растёт, а логика усложняется. За внешне простой веб-страницей обычно стоит большой объём JS-кода, включающий множество операций добавления, удаления и изменения DOM-узлов. Неизбежно возникают ситуации, когда трудно напрямую найти фрагмент кода по JS-коду, но мы можем быстро найти соответствующий DOM-узел через панель Elements инструментов разработчика. В этот момент поиск скриптов через точки останова DOM становится особенно важным. Давайте посмотрим с помощью GIF-демонстрации:


1465008822-9630-YuxebCQCMgq4jvK5LI6jPTzlqfTQ


На рисунке выше показан эффект точек останова, срабатывающих при добавлении, удалении и перестановке порядка дочерних узлов (li) элемента ul. Обратите внимание, что изменение атрибутов или содержимого дочерних узлов не вызывает срабатывания точек останова.


4.2. Прерывание при изменении атрибутов узла (Break on attributes modifications)


С другой стороны, по мере того как бизнес-логика, обрабатываемая фронтендом, становится всё сложнее, усиливается зависимость от хранения определённых данных. Хранение временных данных в (пользовательских) атрибутах DOM-узлов во многих случаях является предпочтительным выбором для разработчиков. Особенно после того, как стандарт HTML5 расширил поддержку пользовательских атрибутов (например, dataset, data-* и т. д.), использование настроек атрибутов стало всё более распространённым. Поэтому Chrome Developer Tools также обеспечивает поддержку точек останова на изменение атрибутов, и эффект примерно следующий:


1465008821-5906-h7u6Z0DnpHguwGwDJQZpmPj0J42w


Этот метод также требует внимания: любые операции с атрибутами дочерних узлов не будут вызывать срабатывание точки останова на самом узле.


4.3. Прерывание при удалении узла (Break on node removal)


Эту DOM-точку останова очень просто установить, и условие срабатывания понятно: когда узел удаляется. Поэтому этот метод обычно используется при выполнении инструкции `parentNode.removeChild(childNode)`. Этот метод используется нечасто.


Методы отладки, представленные выше, в основном относятся к тем, которые мы часто используем в повседневной разработке. При правильном использовании они могут справиться почти со всеми проблемами в нашей повседневной разработке. Однако инструменты разработчика также учитывают больше сценариев и предоставляют дополнительные методы установки точек останова, как показано на рисунке:


1465008821-7630-MdjuibRU233dKyUeriaj5WpdLYeA


5、Точки останова XHR


В последние годы фронтенд-разработка претерпела кардинальные изменения — от почти неизвестности вначале до чрезвычайной популярности сегодня. Ajax обеспечивает работу насыщенных веб-приложений, а мобильные одностраничные приложения WebApp процветают. Всё это неотделимо от объекта XMLHttpRequest, а «XHR Breakpoints» — это функция отладки с точками останова, специально предназначенная для асинхронных операций.


1465008821-4356-PYqD9PZ4YI4Xt1efKzqCJXq87woQ


Мы можем добавить условия точки останова для асинхронных точек останова с помощью кнопки "+" справа от "Точки останова XHR". Когда URL асинхронного запроса соответствует этому условию, логика JS автоматически вызовет точку останова. Демонстрационная анимация не показывает местоположение точки останова, потому что в демонстрации используется инкапсулированный метод ajax из jQuery, а код был минифицирован, поэтому заметный эффект не виден. Фактически точка останова XHR срабатывает на операторе `xhr.send()`.


Сила XHR-точек останова заключается в возможности настраивать правила точек останова, то есть мы можем устанавливать точки останова для группы, одного или даже всех асинхронных запросов — очень мощно. Однако, похоже, эта функция нечасто используется в повседневной разработке, по крайней мере я не использую её часто. Вероятно, есть две причины: во-первых, такой тип отладки с точками останова редко встречается в повседневной бизнес-логике; во-вторых, фронтенд-разработка на данном этапе в основном основана на JS-фреймворках. Даже самый базовый jQuery уже хорошо инкапсулирует Ajax, и очень немногие инкапсулируют методы Ajax самостоятельно. Более того, чтобы уменьшить размер кода, проекты обычно выбирают минифицированные библиотеки кода, что делает отслеживание XHR-точек останова относительно менее простым.


6、Точки останова прослушивателей событий


Точки останова прослушивателей событий, то есть установка точек останова на основе имён событий. Когда событие срабатывает, точка останова останавливается в месте, где привязано событие. Точки останова прослушивателей событий перечисляют все события страницы и скрипта, включая мышь, клавиатуру, анимацию, таймеры, XHR и т. д. Это значительно снижает сложность отладки бизнес-логики, связанной с событиями.


1465008822-3594-6rlkkFx8mygTaKLuNqrMCzEtTrVQ


Демонстрационный пример показывает эффекты точек останова при срабатывании события click и при установке setTimeout. Пример показывает, что после выбора точки останова события click нажатие обеих кнопок вызывало срабатывание точек останова, а при установке setTimeout срабатывает точка останова "Установить таймер".


Отладка — очень важная часть разработки проекта. Она не только помогает быстро находить проблемы, но и экономит время разработки. Освоение различных методов отладки, несомненно, принесёт много пользы вашей карьере. Однако среди такого множества методов отладки выбор подходящего для текущего сценария приложения требует опыта, постоянных проб и накопления.

Автор: Чжэн Уцзян
Источник: http://seejs.me/2016/03/27/jsdebugger/