Menu
Русский

Console и DevTools: отладка JavaScript без console.log

Разбираем методы console и фишки DevTools, которые ускоряют отладку JavaScript в разы — без хаоса из console.log по всему коду.

Консоль — это не только console.log

console.log в JavaScript — первый инструмент отладки, который узнаёт каждый новичок, и последний, от которого многие так и не отказываются. Он работает, но у объекта console есть ещё с десяток методов, которые делают отладку быстрее и нагляднее. А когда освоитесь с самим DevTools — точками останова, стеком вызовов, watch-выражениями — к log будете обращаться заметно реже.

Для начала — небольшой обзор:

index.js
Output
Click Run to see the output here.

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

Как по-быстрому вывести сразу несколько значений

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

index.js
Output
Click Run to see the output here.

Трюк { user, count } — это сокращённая запись объектов: имя переменной становится ключом. В консоли увидите { user: {...}, count: 3 }, а user можно раскрыть и изучить внутренности. При этом структура объекта не теряется — в отличие от варианта, где его приводят к строке.

console.table для массивов объектов в JavaScript

Когда перед вами массив объектов, console.log выдаёт свёрнутую кашу. А вот console.table отрисует всё в виде нормальной таблицы:

index.js
Output
Click Run to see the output here.

В консоли браузера первый вызов выведет все три строки с сортируемыми колонками. Второй — покажет только name и role. Для любых данных табличного вида — ответов API, результатов запросов, распарсенных CSV — это серьёзно упрощает жизнь.

console.dir vs console.log

На первый взгляд они похожи, но с DOM-элементами ведут себя по-разному:

const el = document.querySelector("button");

console.log(el);   // выводит HTML: <button>Click me</button>
console.dir(el);   // выводит представление JS-объекта со всеми свойствами

log показывает элементы как HTML, а вот dir раскрывает сам объект — все свойства, все обработчики событий, все ссылки на вычисленные стили. Когда нужно узнать, какие методы и атрибуты есть у элемента, выручает именно console.dir.

Группировка связанных сообщений в консоли

Во время долгой отладки консоль быстро превращается в свалку. console.group вместе с console.groupEnd собирают связанные сообщения в сворачиваемый блок:

index.js
Output
Click Run to see the output here.

Каждый вызов создаёт именованную группу, которую можно свернуть. Если хочется, чтобы группы по умолчанию были уже свёрнуты, используйте console.groupCollapsed — удобно, когда вы планируете раскрывать только те, что выглядят подозрительно.

Замер времени выполнения через console.time

Для быстрых замеров производительности сложно придумать что-то лучше связки console.time и console.timeEnd:

index.js
Output
Click Run to see the output here.

Метки в time и timeEnd должны совпадать. Можно запускать несколько таймеров одновременно — главное, чтобы у каждого была своя метка. Но если вопрос серьёзнее, чем «тормозит ли этот цикл?», переключайтесь на вкладку Performance в DevTools: там вы получите полный таймлайн и flame-график.

Ассерты: логируем, только когда что-то пошло не так

console.assert выводит сообщение только в том случае, если условие ложно. Это тихий способ оставить проверки-страховки в коде, не засоряя консоль, когда всё в порядке:

index.js
Output
Click Run to see the output here.

Хорошо подходит для инвариантов, которые обязаны выполняться всегда. Плохо — для ситуаций, где сбой вполне законен: в таких случаях лучше бросать ошибку.

Стек вызовов по запросу

console.trace выводит текущий стек вызовов, ничего при этом не выбрасывая. Удобно, когда нужно понять, кто вообще вызвал функцию:

index.js
Output
Click Run to see the output here.

Вывод идёт в порядке inner → outer → (top level). В реальном приложении именно так вы обнаруживаете, что обработчик клика, который вы отлаживаете, дёргается сразу из трёх разных мест.

Оператор debugger

Самый быстрый способ поставить JavaScript на паузу — одно-единственное слово:

function computeTotal(items) {
    const subtotal = items.reduce((s, i) => s + i.price, 0);
    debugger;
    return subtotal * 1.08;
}

When DevTools is open, debugger; acts like a breakpoint — execution pauses on that line and you get the full debugger: variables in scope, the call stack, step-over and step-into controls, the ability to evaluate expressions against the current state. When DevTools is closed, debugger; does nothing.

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

Не забудьте убрать debugger перед коммитом. А ещё лучше — расставляйте точки останова прямо в DevTools, кликая по номеру строки на панели Sources.

Фишки Chrome DevTools, о которых стоит знать

Несколько возможностей, которые многие годами не замечают:

  • Условные точки останова: кликните правой кнопкой по номеру строки в Sources и задайте условие, например user.id === 42. Брейкпоинт сработает только когда условие истинно.
  • Logpoints: в том же меню — «Add logpoint». Выводит сообщение без паузы и без правок в коде.
  • $_ в консоли: результат последнего вычисленного выражения. Что-то выполнили — и через $_ снова достаёте результат.
  • $0: текущий выбранный элемент на панели Elements. $0.textContent покажет содержимое того, по чему вы кликнули.
  • Сохранить как глобальную переменную: правый клик по любому значению в консоли и «Store as global variable». Получите temp1, temp2 и так далее — ковыряйтесь на здоровье.
  • Network → Copy as fetch: превращает любой запрос в вызов fetch(), который можно вставить в консоль и подправить.

Ни одна из этих штук не обязательна. Но каждая экономит время, когда входит в мышечную память.

Наводим порядок перед продакшеном

Забытые console.log безобидны в разработке и шумят в продакшене. Пара привычек, которые помогают:

  • Включите правило линтера (no-console в ESLint), которое ловит случайные логи, с исключениями для warn и error.
  • Оборачивайте подробное логирование в проверку: if (process.env.NODE_ENV !== "production") console.log(...).
  • Для трассировочного вывода используйте console.debug — большинство сборщиков и систем сбора логов умеют его отфильтровывать.
  • Ещё лучше — заведите небольшой модуль-логгер (или возьмите библиотеку вроде debug), чтобы включать и выключать категории логов, не трогая код.

Логирование не бесплатное. Каждый вызов сериализует аргументы и пишет в буфер. В горячем цикле забытый лог способен ощутимо замедлить код.

Дальше: регулярные выражения

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

Часто задаваемые вопросы

Чем console.log отличается от console.dir?

console.log выводит значение так, как браузер считает нужным — например, DOM-элемент показывается как HTML-разметка. А console.dir всегда показывает объект именно как JS-объект со всеми его свойствами. Если нужно посмотреть не разметку элемента, а его свойства — берите console.dir.

Как отлаживать JavaScript в Chrome DevTools без console.log?

Откройте вкладку Sources, найдите нужный файл и кликните по номеру строки — там поставится точка останова (breakpoint). Когда выполнение до неё дойдёт, код встанет на паузу, и вы сможете посмотреть значения переменных, пройтись по шагам и выполнить любое выражение прямо в консоли. Ещё вариант — воткнуть debugger; прямо в код, это тоже сработает как breakpoint.

Как замерить время выполнения JavaScript-кода?

Оберните нужный кусок в console.time('метка') и console.timeEnd('метка') с одинаковой меткой — в консоль выведется прошедшее время в миллисекундах. Если нужна более глубокая картина, открывайте вкладку Performance в DevTools: она запишет flame chart всего, что происходило во время выполнения.

Для чего нужен console.table?

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

Учитесь программировать с Coddy

НАЧАТЬ