javascript

Отладка JavaScript в Chrome DevTools для начинающих фронтендеров

  • суббота, 22 февраля 2025 г. в 00:00:12
https://habr.com/ru/companies/intec_balance/articles/884482/

Здравствуй, Хабр! Я – Рома, front-end разработчик в компании «АйТи-Баланс». Мне не понаслышке известно, насколько ресурсозатраным (в плане времени и сил) может быть поиск и исправление ошибок в JS. Новичкам этот процесс может показаться неподъёмным камнем, но только до знакомства с отладкой в инструментах разработчика, встроенных в браузер. О ней я и расскажу, причём затрону не console.log, а куда более эффективную альтернативу.

как chatgpt видит отладку в Chrome DevTools
как chatgpt видит отладку в Chrome DevTools

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

Мы будем работать с кодом. Предполагается, что вы уже знакомы с HTML, CSS и JavaScript. По ходу чтения будут встречаться названия разных элементов – в скобках рядом с ними будет перевод. Это для тех пользователей, у кого язык браузера выставлен на английский. Теперь к делу!

Воспроизводим проблему

Есть страница «Сумма и среднее». На ней пользователь вводит два или три числа, нажимает на кнопку и получает их сумму и среднее. Должно быть, например, так:

страница с вычислением суммы и среднего значения
страница с вычислением суммы и среднего значения

Но на деле получается вот так:

конкатенация
конкатенация

Цифры просто объединяются в одно число. Конкатенация вместо сложения. Из-за этого и среднее вычисляется неправильно.

Вот HTML-код: index.html

CSS: style.css

И JavaScript, который проверяет, сколько значений ввёл пользователь (должно быть минимум 2), и выполняет расчеты: script.js

Исходники у нас на руках. Теперь давайте выясним, в чём проблема, и исправим её! Для этого нам понадобятся DevTools – инструменты разработчика, встроенные в браузер.

Я рекомендую сохранить этот код и своими руками проделать всё, что будет дальше в статье. Практикой усваивается лучше, чем просто чтением.

Открываем инструменты разработчика

Далее я покажу всё на примере Chrome DevTools. Однако вы можете пользоваться любым другим современным браузером, который вам по душе: Firefox, Safari, Edge и т.д. В них есть аналогичные инструменты, и сами принципы +/- такие же.

Некоторые браузерные расширения могут нарушить ход отладки. Чтобы избежать этого, откройте страницу в режиме инкогнито. Там ничего лишнего не загрузится.

Итак, мы на «Сумме и среднем». Открываем DevTools. В Хроме это можно сделать несколькими способами:

  • Нажать на клавишу F12.

  • Нажать сочетание клавиш. На Windows и Linux: Ctrl + Shift + I; на macOS: Cmd + Shift + I.

  • Кликнуть правой кнопкой мыши -> выбрать «Просмотреть код» (Inspect).

  • Открыть меню (три вертикальных точки в правом верхнем углу) -> выбрать «Дополнительные инструменты» (More Tools) -> «Инструменты разработчика» (Developer Tools).

Должно быть как-то так:

DevTools можно закрепить справа, внизу или слева, либо вообще перенести в другое окно – как вам удобно. Для этого:

  1. Откройте меню дополнительных настроек (три вертикальные точки в правом верхнем углу инструментов).

  2. Кликните на значок с нужным размещением.

Отлаживаем код

Чтобы найти и устранить баг, можно прописать в скрипте кучу операторов console.log, но тогда всё затянется надолго. Гораздо проще, быстрее и эффективнее воспользоваться точками останова (breakpoints). Они прерывают выполнение кода на нужном вам месте и позволяют проверить каждый следующий шаг или функцию, а также значения переменных, доступных на данный момент. Это и поможет нам решить проблему! Даже если вы сейчас не понимаете, о чём речь, то не переживайте – на практике станет яснее.

В окне DevTools перейдите во вкладку «Источники» (Sources) – там мы и будем отлаживать код. Вы увидите три раздела:

  • Слева – навигатор (Navigator). Тут все файлы, запрошенные текущей страницей. Этот раздел можно свернуть или развернуть, нажав на кнопку «Скрыть навигатор» (Hide navigator).

  • По центру – редактор кода (Code Editor). Здесь будет содержимое файлов, на которые вы кликните в навигаторе. Внизу этого раздела есть кнопка { }, которая форматирует JS-код в полноценный вид, если он был минифицирован.

  • Справа или внизу – панель отладки (Debugger). Тут мы будем инициировать точки останова и просматривать содержимое переменных. Если отмасштабировать окно инструментов достаточно широко, то этот раздел будет справа, в противном случае – внизу. Его можно свернуть или развернуть, нажав на кнопку «Скрыть отладчик» (Hide debugger).

В Chrome DevTools есть девять типов точек остановы. Мы изучим две самые известные: для прослушивателя событий (“событийные”) и для строк кода (“строчные”).

Точка останова №1

Все вычисления выполняет script.js – следовательно, проблема где-то в нём. Выбираем этот файл в навигаторе. Его содержимое появится в редакторе кода:

Сумма рассчитывается неправильно, когда мы кликаем на «Вычислить сумму и среднее» – значит, мы остановимся на этом событии и далее вручную пройдёмся по остальному коду. Проверим порядок его выполнения и значения, которые будут присваиваться переменным. Выставляем “событийную” точку останова в панели отладки:

  1. Откройте блок «Точки останова прослушивателя событий» (Event Listener Breakpoints).

  2. Откройте категорию событий «Мышь» (Mouse).

  3. Установите флажок на click. Так, DevTools будет приостанавливаться на любом прослушивателе событий click.

Теперь воспроизводим ошибку:

  1. Убедитесь, что вы ввели минимум 2 числа. В противном случае, никаких расчётов не будет – JS в конце концов просто вернёт соответствующее уведомление.

  2. Кликните на «Вычислить сумму и среднее».

Нажатие кнопки связано с функцией checkNums, поэтому отладчик остановился на её начале.

Навигация по коду

Мы на строке 6, но она ещё не выполнена. Здесь будет вызвана функция allNumsArray. Зайдём в неё, нажав на кнопку «Войти в следующий вызов функции» (Step into next function call), которая находится наверху панели отладки. Этот элемент управления позволяет пройтись по коду строка за строкой.

Мы внутри allNumsArray. Она возьмёт значения всех трёх “инпутов” (поочерёдно вызвав функции getNum1, getNum2 и getNum3), сохранит их в виде массива и вернёт его.

Глядя на этот участок кода, мы можем сказать, что здесь никаких ошибок нет. Когда вы внутри функции и уверены, что она работает правильно, то есть 2 варианта:

  • Пройтись по ней строка за строкой до самого конца. Это долго и совершенно не нужно, если с функцией всё нормально.

  • Выйти из неё. Вы минуете выполнение функции, в которой находитесь, и перейдёте сразу к результатам её работы.

Чтобы сэкономить время (и изучить новую кнопку), мы воспользуемся вторым вариантом. Нажмите на кнопку «Выйти из текущей функции» (Step out of current function) – она также наверху панели отладки.

Мы пропустили выполнение allNumsArray и сразу получили результаты. Массив со значениями всех трёх “инпутов” присвоен переменной allNums. Шестая строка выполнена, и мы остановились на седьмой:

Кстати, результаты видны не только справа от выполненной строки, но и в «Области действия» (Scope). Этот блок находится в панели отладки, и показывает значения переменных, доступных на данный момент. Для allNums уже всё вычислено, ткогда как для actualNums – ещё нет:

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

3.2-6_countActualNums.js

Здесь тоже всё нормально: countActualNums получит массив allNums и подсчитает, сколько в нём реальных значений (т.е. пустые строки не учтутся), а затем вернёт их количество. Если вы находитесь перед функцией (ещё не зашли в неё), но уверены, что она работает правильно, то у вас вновь есть выбор:

  • Зайти в неё и построчно пройти до конца. Нет нужды тратить на это время, если с функцией всё хорошо.

  • “Перешагнуть” через неё – пропустить выполнение и сразу получить результаты.

Мы изучили countActualNums и уверены, что она работает правильно. Сэкономим время и “перешагнём” через неё, нажав на «Пропустить следующий вызов функции» (Step over next function call). Эта кнопка, как и остальные элементы управления, находится наверху панели отладки.

Мы миновали выполнение countActualNums. Результаты показаны справа от строки 7. Изменения видны и в «Области действия» (Scope) – у переменной actualNums появилось значение:

Теперь мы остановились на системе уведомлений. Она сработает, если пользователь отправил только одно число или вообще ни одного.

В этом месте будут работать и step into и step over, так как нет вызова функции/метода, а просто идет код.

Точка останова №2

Теперь черёд функции mathDoer. Вначале рассмотрим её, и только потом будем действовать.

3.3-1_mathDoer.js

Здесь вычисляются сумма и среднее. Нам нет нужды проходить строки 44-48 одна за другой. Там вызываются уже знакомые нам функции, с которыми всё нормально: getNum1-3, allNumsArray, countActualNums. Самое интересное для нас – это строка 50, где и складываются значения, введённые пользователем:

3.3-2_line50.js

Чтобы сэкономить время, выставим “строчную” точку останова:

  1. В окне DevTools наведите курсор на цифру 50, которая слева от кода. Это номер строки.

  2. Кликните по этой цифре. Поверх неё появится синяя метка, которая означает, что на данной строке теперь есть точка останова.

Как альтернатива, вы можете прописать специальное слово debugger перед строкой, на которой отладчик должен остановиться. Однако это выражение придётся удалить вручную, когда оно станет не нужным. Мы будем придерживаться только “строчной” точки останова.

Проверяем значения переменных

Если мы видим, какие данные присваиваются переменным, то можем быстрее обнаружить проблему. Как вы помните, «Область действия» (Scope) показывает значения всего, что доступно на данный момент. Кроме того, есть и блок «Выражения контрольного значения» (Watch) – он позволит нам не только мониторить переменную, но прописать и отслеживать результат любого выражения/вызова метода. Вызывать методы в Watch не всегда хорошо, так как некоторые вызовы методов могут вызывать изменения на странице в целом.
 Пользуемся:

  1. Разверните этот блок в панели отладки.

  2. Нажмите на значок «+», добавьте выражение typeof num1. Оно будет показывать тип операнда num1.

  3. Повторите п.2, но уже для num2, num3 и sum.

  4. Можно ещё добавить выражения num1, num2, num3 и sum. Они будут показывать значения этих операндов.

Всё готово. Теперь нажимаем на синюю кнопку «Продолжить выполнение скрипта» (Resume script execution) – она перенесёт нас на ближайшую точку остановы, т.е. на строку 50.

Строки 44-48 выполнены. Результаты справа от них, а также в «Выражениях контрольного значения» (Watch) и «Области действия» (Scope):

И там, и там, и там заметна одна деталь: значения переменных num1-3 заключены в кавычки. Выражения typeof говорят ещё понятнее – string. Данные строковые, а не числовые.

Можем даже перепроверить всё в консоли DevTools:

  1. Нажмите Esc, чтобы открыть её. Консоль появится внизу окна DevTools.

  2. Поочерёдно введите имя переменных, и получите их значения.

  3. Поочерёдно введите typeof для этих переменных, и получите тип присвоенных им данных.

  4. Закройте консоль (Esc).

Так произошло потому, что у элементов input есть атрибут value, который по умолчанию выставлен на text. В нашем HTML-коде это не изменено, поэтому цифры из “инпутов” были предоставлены в строковом формате. А раз JS получил строковые данные, то он их конкатенировал, а не сложил друг с другом. Вот причина нашей проблемы!

Исправляем баг

Решение – превратить строковые данные в числовые. Для этого воспользуемся глобальной функцией parseFloat. Она обработает как целые числа, так и числа с плавающей точкой. Давайте заранее проверим, не ошибаемся ли мы:

  1. Откройте консоль DevTools (Esc).

  2. Введите, к примеру parseFloat(num1). Вместо num1 можете подставить num2 или num3.

  3. Нажмите Enter.

Действительно, мы получили число, а не строку. При этом в самом коде ничего не поменялось.

Теперь протестируем решение целиком, но в «безопасном режиме»:

  1. В редакторе кода DevTools измените строки 44-46 в файле script.js так, как на примере ниже. Выражение parseFloat() || 0 будет работать даже в том случае, если пользователь оставил одно поле пустым. 

  2. Сохраните исправления, нажав Ctrl + S (Windows, Linus) или Cmd + S (macOS). Они применятся только к коду, который выполняется в вашем браузере. Исходный файл на компьютере останется нетронутым.

3.5-2_fix.js

Нажмите на «Отключить точки останова» (Deactivate breakpoints), чтобы они не мешали. Заметка на будущее: активировать их можно той же кнопкой.

И нажмите на «Продолжить выполнение скрипта» (Resume script execution).

Сработало! Теперь сумма и среднее вычисляются правильно:

А если оставить одно поле пустым? Ничего не сломается, все расчеты будут верны:

Пользователь может ввести числа с плавающей точкой. В таком случае всё тоже будет нормально:

Вы можете зафиксировать эти изменения, внеся их в исходный файл script.js. Кроме того, в блоке «Выражения контрольного значения» (Watch) остались следы от нашей практики. Вы можете:

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

  • Удалить их всех. Для этого кликните правой кнопкой мыши по любому выражению и выберите «Удалить все выражения контрольного значения» (Delete all watch expressions).

Ура!

Поздравляю! Если вы добросовестно освоили статью от начала до конца, то у вас появились крепкие базовые навыки по отладке JS с помощью DevTools. Они сохранят вам уйму времени, сил и нервов.

Что я порекомендую напоследок:

Удачи вам, а также быстрой и эффективной отладки в будущих проектах! :)

Читать предыдущую статью: «Академический минимум js-разработчика: базовые концепции».