Chrome DevTools: Хитрости при отладке

в 14:24, , рубрики: chrome devtools, debug, javascript, отладка

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

В этой заметке я бы хотел остановиться на различных нюансах, полезных при отладке. Какие-то из них я почерпнул в сети (например в комментариях на Хабре), до каких-то додумался сам. Надеюсь вы найдёте для себя что-нибудь полезное.

Все горячие клавиши в статье будут даны для linux/windows.

PopUps, popovers, dropdowns и прочие "всплывашки"

Начну с простого. Я думаю многие сталкивались с ситуацией, когда у вас есть какая-нибудь "всплывашка", и вам нужно что-нибудь в ней поковырять. Но вот незадача - стоит убрать фокус из окна вкладки, как всплывашка тут же пропадает. Если код полностью под вашей властью, то можно просто отключить механизм сокрытия на onBlur. А если нет?

Вот простое решение:

  • Открываем console

  • Запускаем: setTimeout('debugger;', 3_000)

  • Успеваем за эти три секунды активировать всплывашку

  • debugger тормозит вкладку

  • Всплывашка в вашем полном распоряжении

Бесконечный цикл

Иногда случается так, что в результате ошибки, ваш код бесконечно что-нибудь считает. И конца и краю этому нет. Например баг при работе с счётчиками для for(;;). Ну или какие-нибудь реактивные примитивы обновляют друг друга по кругу. Причин может быть много. Главное, что с этим делать? Думаю многие заметили, что даже попытка обновить страницу часто не помогает. Страница просто зависает, вкладка не закрывается, творится чёрт знает что. Да ещё и кулер бешено гудит.

Начнём с того - как же убить вкладку?

  • Запускаем Task Manager (Shift + Esc ). Его можно найти в "главном меню" - "More Tools" - "Task Manager".

  • Находим искомую вкладку в списке, выделяем.

  • Жмём кнопку "End Process". Вкладка убита.

    Chrome DevTools: Хитрости при отладке - 1

Хорошо, а что если мы не хотим её убивать?

  • Открываем "Sources"

  • Кликаем на "Pause"

Chrome DevTools: Хитрости при отладке - 2

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

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

Вы можете попробовать запустить что-то вроде throw 'error', но скорее всего это вам ничего не даст, т.к. ваши команды в консоли обёрнуты в try-catch. Но можно сломать какой-нибудь объект. Предположим у вас там есть объект obj, и у него есть поле-метод field. Код использует его так: obj.field(). Прекрасно, пишем obj.field = null , запускаем JS, код падает, в консоли ошибка, вечный цикл побеждён. Понятное дело, что способов всё поломать тысячи, просто выберите нужный.

Деактивация breakpoint-а

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

  • Вот эти галочки справа:

    Chrome DevTools: Хитрости при отладке - 3
  • Вот это контекстное меню:

    Chrome DevTools: Хитрости при отладке - 4
  • Просто Shift + LeftClick по панели breakpoint-а:

    Chrome DevTools: Хитрости при отладке - 5

Логирование при помощи breakpoint-ов

Тут всё просто. Не обязательно расставлять в кодовой базе console.log(), когда можно это сделать прямо в DevTools. Дело в том что у breakpoint-ов бывают условия:

Chrome DevTools: Хитрости при отладке - 6

Если условие задано, то breakpoint остановит исполнение JS только если его значение truthy. Напишите в условие console.log(whatever). Всё. Т.к. console.log всегда возвращает undefined то ваш breakpoint никогда не остановит JS, но зато всегда будет послушно логировать.

HotFix-ы посредством breakpoint-ов

Механизм тот же самый. Предположим вы отлаживаете один баг, но в процессе отладки обнаружили другой, который всё портит, и вы не хотите на него отвлекаться. А ещё вы не хотите перезагружать вкладку, т.к. эту ситуацию вы потом уже не воспроизведёте. Что делать? Можно в breakpoint-условии написать что-нибудь, что чинит второй баг.

Например, что-нибудь ломается из-за отсутствующего метода. Ок, напишите в условии (obj.nonExistingMethod = () => null) && null. Код временно "починился". && null нужен только для того, чтобы breakpoint не останавливал исполнение JS.

Chrome DevTools: Хитрости при отладке - 7

Таким образом можно добиться очень многого. Зависит уже от вашей фантазии и сложности отладки. Ключевое:

  • нет нужды перезагружать вкладку (это может быть бесценным).

  • breakpoint-условие будет послушно запускаться всякий раз когда JS-интерпретатор будет добираться до breakpoint-а. По сути это аналогично тому что вы добавили строку кода ровно туда, куда нужно, ничего по факту не добавляя.

Breakpoint посреди строки

Не все замечали, но Chrome DevTools позволяют выставить breakpoint не на всю строку, а в какую-нибудь её часть:

Chrome DevTools: Хитрости при отладке - 8

Это может сэкономить вам кучу времени.

Имена собственные

Если вы используете sourceMaps, то код, которые на самом деле исполняется, и тот который вы видите перед глазами могут очень сильно отличаться. В частности это касается имён локальных переменных. Пример:

Chrome DevTools: Хитрости при отладке - 9

Что будет если в консоли выполнить setState?

Chrome DevTools: Хитрости при отладке - 10

И как теперь это дебажить? А чёрт его знает. Но могу дать пару советов.

1-й: поищите настоящие имена вот здесь:

Chrome DevTools: Хитрости при отладке - 11

2-й: отключите sourceMaps (это можно делать live, без перезагрузки страницы):

Chrome DevTools: Хитрости при отладке - 12

SourceMap очень часто усложняют отладку до уровня nightmare. У @vintage где-то (где кстати?) была хорошая статья по этому поводу. Там объясняется почему SourceMap такие плохие, когда дело касается отладки. Я сам то и дело включаювыключаю эту галочку, в зависимости от обстоятельств.

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

BreakPoint-ы и PrettyPrint

Минифицированный код можно отформатировать так, чтобы с ним можно было работать:

Chrome DevTools: Хитрости при отладке - 13

Но очень часто даже после этого с ним невозможно работать. BreakPoint-ы ставятся куда попало (куда не кликай он появляется либо вначале файла, либо в его конце). Отладка просто сходит с ума (к примеру всегда указывает на первую строку файла).

Что делать?

  • Открыть этот локальный файл в редакторе

  • Отформатировать код файла (например Prettier-ом)

  • Сохранить (да, даже если это сторонняя библиотека)

  • Убедиться что пересборка webpackrollupwhatever учла это изменение

Теперь вам не нужен DevTools-ий pretty print. Можно debug-ить напрямую.

Перехват запросов

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

Находим нужный запрос в network-вкладке и наводим на него мышью:

Chrome DevTools: Хитрости при отладке - 14

Кликаем по 1-й (не обязательно) из ссылок, попадая в то место, где этот запрос был вызван. Ставим точку останова. Воспроизводим нужные действия в UI, чтобы этот запрос перевызвать.

Chrome DevTools: Хитрости при отладке - 15

В этом месте мы можем подправить параметры ещё до того как запрос ушёл на сервер. Отсюда же можно отследить то место, где будет обработан результат запроса:

Chrome DevTools: Хитрости при отладке - 16
Chrome DevTools: Хитрости при отладке - 17

Наверняка есть и более удобные способы перехватить запрос. Поделитесь вашим рецептом в комментариях!

Race Condition

Что делать, если у вас есть сложная многостадийная асинхронная логика и с ней что-то не так. Например у вас race condition. Как проще всего воссоздать условия для его обнаружения? Я думаю тут есть множество рецептов. Здесь я остановлюсь только на одном из них. В network вкладке есть такой dropdown:

Chrome DevTools: Хитрости при отладке - 18

Наверняка многие из вас им уже пользовались. Offline режим позволяет отловить ошибки при проблемах с сетью. Slow 3G проследить как быстро грузится ваш сайт при медленном интернете. Но обратите также внимание на секцию "Custom". Это заданные вручную режимы. Просто нажмите "Add" (внизу списка), чтобы добавить свой.

Какие режимы использую я?

  • Never: максимальная задержка. Просто выставите огромное число. Например сутки. Теперь любой запрос повисает до тех пор, пока вы не выключите этот режим. Запросы не "умирают", а именно повисают. Это даёт вам неограниченное время для отладки какой-нибудь промежуточной стадии вашей зубодробительной логики.

  • 2530sec latency: просто большая задержка. Актуальна когда вы отлаживаете "плавающий" баг. То он есть, то его нет. Или, скажем, когда вам нужно успеть сделать какое-нибудь быстрое действие мышью между двумя запросами. Или более пристально проследить что происходит, как бы в режиме slow-mo.

Disable cache

Думаю большинство из нас знакомы с этой галочкой:

Chrome DevTools: Хитрости при отладке - 19

Здесь я хотел бы отметить, что не стоит на постоянной основе ей пользоваться. Дело в том, что такое поведение браузера очень далеко от нормального. Браузер перестаёт пользоваться не только старым кешем, оставшимся от предыдущей страницы, но и новым. Если покажете картинку, удалите её, а потом снова создадите с тем же SRC, то у вас будет два запроса.

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

Помимо прочего это мешает работать любой логике где есть подготовительные стадии с прогревом кеша. Например когда перед показом изображения вы где-нибудь успеваете его загрузить посредством new Image().

В целом рекомендую поглядывать на запросы во вкладке network. Например можно случайно обнаружить, что отключён gzip/brotli. Или что CDN перестал присылать cache-control заголовок. Или что ещё вчера страница загружала 1 MiB, а сегодня 12 MiB (например какой-нибудь серверный endpoint стал присылать тонны JSON-а).

HI-DPI

Что делать, если у вас обычный монитор, а клиенты жалуются на мыло на мобильных устройствахretina экране? Для начала активируйте нужный DPR режим:

Chrome DevTools: Хитрости при отладке - 20

Теперь браузер имитирует HI-DPI. И всё стало таким угловатым (нюансы сглаживания при resize). Но как проверить настоящую картинку?

  • Открываем палитру команд (Ctrl+P)

  • Ищем: capture area screnshoot

Chrome DevTools: Хитрости при отладке - 21
  • Выделяем мышью нужную область экрана, сохраняем в файл

  • Открываем файл и наслаждаемся огромной картинкой. Смотрим правда ли она "мыльная"?

Обычными системными скриншотами, разумеется, этого не достичь. Полагаю этот же рецепт работает и в обратную сторону (имитация 1х экрана).

Это всё?

Если вам понравился этот материал и вы хотите продолжения - дайте знать. У меня ещё много всего в черновиках. Если у вас есть свои трюкирецептыхаки - пишите их в комментариях. Думаю многие найдут их полезными и применят в деле.

Если вы нашли синтаксическуюстилистическую ошибку (или тонну таких ошибок) прошу обращаться в личку (а не в комментарии).

Автор: Зубашев Степан

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js