Русский
Русский
English
Статистика
Реклама

Отладка javascript

Обработка ошибок в JavaScript

07.09.2020 12:20:38 | Автор: admin

Привет, Хабр!

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

Итак, для того, чтобы вам было понятно, в чем суть и есть ли что-то новое для вас, ниже представлена структура заметки:

  • Ошибка в JavaScript?

  • Железобетонные методы обработки ошибок

  • Облегчаем себе жизнь

  • Ошибки зависимостей

Ошибка в JavaScript?

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

Ошибка в JS - это выбрасывание исключения (throw of an exception). Исключение должно быть обработано программой, в противном случае интерпретатор вернет нас на то место, где это исключение было выброшено. По умолчанию исключение выбрасывает объект Error.

Неважно, пишете ли вы Frontend или Backend, подход к обработке один поймать злосчастное исключение и обработать. Обрабатывать нужно все, особенно в проде.

Сразу просветим пару нестандартных ситуаций (кому как):

  • ошибка извне программы,

  • терминальная ошибка.

Терминальная ошибка это код ошибки, который возвращает ОС или демон.

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

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

Самый главный вопрос когда возникает ошибка?

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

  • Синтаксическая ошибка (забыли запятую, скобку и т.д.)

  • Ошибка интерпретатора (обращение к несуществующей переменной и т.д.)

  • Ошибка исполнения (тип переменной оказался, например, undefined) самая частая в работающем приложении

  • И еще несколько вариантов, с которыми вы можете ознакомиться тут.

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

Железобетонные методы обработки ошибок

Чтобы сражаться с врагом, нужно знать его в лицо, поэтому ниже основные свойства объекта Error:

  • name название ошибки;

  • message текст выбрасываемой ошибки;

  • stack стек вызовов, приведших к ошибке.

Важно заметить, что свойства не стандартизированы, а также помним, что исключение может быть любым типом данных.

Из этого набора информации при обработке ошибок самым важным является их классификация. По моему мнению, если удалось правильно классифицировать выброшенное исключение это 80% работы. Остальные 20% завязаны на правильной обработке, ведь каждое приложение это бизнес, следовательно, минимизация ошибок в бизнесе прирост конверсии.

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

  • стек вызовов, приведших к ошибке;

  • уровень ошибки (фатальная, критическая, баг, неожиданная и т.д.);

  • класс ошибки (сетевая, сервисная, пользовательская и т.д.);

  • хранение ошибки для анализа и пост-обработки;

  • логирование;

  • профилирование / метрика.

Из всего обилия существующих инструментов выбирать нужно именно по этим критериям. Разница инструментов, как правило, в том, что одни заточены под разработку приложения, а другие под работу приложения в релизе. Суть одна, но какому-то из критериев просто уделяется больше внимания.

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

Придерживаясь методологий SOLID и DRY, нам следует внедрить наш обработчик (middleware) на самый верхний уровень и уже оттуда обрабатывать все ошибки, которые прошли мимо. Middleware может быть как написанный самостоятельно, так и из библиотеки. Ниже примеры.

Для Node.js

Для Vanilla JS

Для React

Для Angular

Для Vue

Данные примеры касаются верхнеуровнего отлова и обработки ошибок, но возникает резонный вопрос: как быть с частными случаями, встречающимися в парадигме JavaScript? Ниже несколько примеров.

Всегда оборачивайте асинхронный код в trycatch, а также вызовы сторонних библиотек.

Вот пример:

// ...const middlewareRequest = async (req) => {  try {    const { data } = await axios.get(req);        return data;  } catch (err) {    throw new Error(err);  }}// ...

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

То же касается и работы с событийной моделью: можно назначать middleware через Функции Высшего Порядка в будущем это позволит вам быстро масштабироваться.

Пример обработки глобального события:

// ...const wrapEventWithExcpetionHandler = (middleware) => (e) => {  const { error } = e; // предположим, что ошибка в этом поле    if (error) {    throw new Error(error);  }    try {    return middleware(e);  } catch (err) {    throw new Error(err);  }}window.addEventListener('mousemove', wrapEventWithExceptionHandler(middlewareGlobalMouseMove));// ...

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

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

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

Так для чего же нужны эти приемы?

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

Работайте с DevTools и выбрасывайте исключения, другие разработчики будут вам благодарны, опираясь на этот гайд. Обязательно ознакомьтесь, если не знали, вот пример:

// .../* обычный console.log может превратиться в нечто большее *//*  как правило, начинающие программисты логируют по одной переменной,  мы же можем форматировать строки с любым количеством аргументов*/console.log('Check:\r\n  username - %s\r\n  age - %i\r\n  data - %o', 'Mike', 23, {status: 'registered'});/*Check:  username - Mike  age - 23  data - {status: "registered"}*//* выводить таблицы массивов */console.table([{username: 'Mike', age: 23}, {username: 'Sarah', age: 46}]);/* или просто логировать данные в их первоначальном виде */console.dir(document.body.childNodes[1]);// ...

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

Облегчаем себе жизнь

1. Рекомендую взять за правило: перед началом каждой разработки централизовать любое логирование, особенно ошибок. С этой задачей помогут справиться библиотеки по типу log4js. Это сразу даст вам понять, ошибка в вашем приложении, либо извне.

2. Используйте Брейкпоинты в DevTools! Это важно уметь делать. Это как машина времени программы, вы останавливаете интерпретатор на нужной строчке и вам даже не нужна консоль просто смотрите значения переменных и поймете, что не так. Делается это простым кликом на нужной строчке во вкладке Source. Выбираете нужный файл, ставите брейкпоинт и перезапускаете программу. Для удаления брейкпоинта кликните на ту же строчку.

3. Стараемся перехватывать все ошибки и исключения на верхнем уровне.

4. Хранение ошибок на сервере больше относится к проду, но имеем в виду, что готовый инструмент прекрасно справляется с данной задачей (см. ниже).

5. Профилирование тема тоже непростая, если вы знаете, что это измерение времени от начала до конца исполнения монады, вы уже на полпути. К счастью, DevTools позволяют делать замеры без вмешательства в код.

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

Для ПРОДвинутых

Если вы уже как рыба в воде при работе с ошибками в JS, рекомендую посмотреть на сервисы для автоматизации сбора и ведению статистики ошибок.

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

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

Также рекомендую ознакомиться на досуге с Graphana, это за рамками статьи, т.к. относится не только к JavaScript, но очень хорошо коррелирует с нашей темой и позволяет отображать на графиках текущее состояние приложений, слать уведомления в чат об ошибках и не только.

Ошибки зависимостей

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

Тут нет выработанного универсального решения для отлова или же игнорирования, т.к. многое зависит непосредственно от сборки самого пакета. Какие советы тут можно дать? Их немного:

  • Самым важным в логировании исключений являются уровни ошибок. Вы можете задавать их посредством встроенного console (log, warn, error, info), либо в сторонних библиотеках (см. выше log4js). Здесь решением проблемы является максимальное разделение ошибок вашего приложения и стороннего, но не переборщите, ведь могут быть действительно важные исключения.

  • Разделяйте ваши сборки на production/development/test и используйте source-map во время разработки либо пре-релиза, это позволит вам получать более детальную информацию в бою о том, что пошло не так с информативным стеком ошибки.

  • Другим способом в перехвате ошибок зависимостей является реальное устранение проблемы, например, посредством Pull Request. Для ленивых можно использовать Fork с фиксом, но тогда его нужно поддерживать, а некоторые проекты не всегда позволяют это делать.

  • Ну, и самым изощренным и неочевидным является использование соответствующих надстроек для babel. Транспайлинг посредством babel работает через AST, который в первом приближении разбирает весь код JavaScript на дерево с вершинами. Есть специальные плагины, которые делают необходимые обертки для удобства разработчиков, по типу полифиллов, перегрузок, а также оборачиванию в специальные конструкции. Оборачивать можно, как вы догадались, и обработку ошибок, но данное решение должно иметь острую необходимость, просто имейте это в виду.

Заключение

Выше были рассмотрены вполне стандартные методы обработки ошибок, а также продемонстрированы примеры техник с кодом для популярных пакетов. Дополнением выступают инструменты по автоматизации сбора и обработки ошибок. Подробную информацию читайте по ссылкам.

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

Автор: Ришат Габайдуллов, Руководитель группы практики Frontend компании Рексофт.

Подробнее..

Основы отладки клиентских JS-приложений

03.02.2021 16:18:50 | Автор: admin

Процесс написания и выполнения программного кода почти всегда сопряжён с необходимостью искать и исправлять ошибки. И в целом процесс отладки приложений выглядит несложно:

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

Меня зовут Артём, я работаю фронтенд-разработчиком в FunBox. Мы делаем продукты для мобильных операторов: различные порталы, геосервисы, платежи, мобильную рекламу и многое другое. Вполне возможно, вы пользуетесь нашими продуктами каждый день или нет тут у меня NDA. В компании мы считаем, что развитая инженерная культура это неотъемлемая часть хороших продуктов. И важный элемент такой культуры уметь записывать всё важное и потенциально полезное для коллег. Эту статью я опубликовал во внутренней базе знаний для коллег-фронтендеров, которые только осваивают основы создания сложных и насыщенных кодом клиентских JS-приложений. Надеюсь, будет полезно и вам.

Общие практики

Глобально все методы отладки делят настатическиеидинамическиев зависимости от того, исполняется ли программный код. При статическойотладке само ПО фактически не задействовано. В процессединамическойотладки программа запущена и выполняется.

Статическая отладка приложений

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

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

Usr A:Привет всем! Я запускаю проект, и появляется ошибка"Cannot read property xxx of yyy". Кто-нибудь знает, что не так?
Usr B:Привет! Да, нужно зайти в файлconfig/build-config.jsи убрать строчкуenableRandomErrors: true

Но не стоит спамить чат вопросами о каждой ошибке. Лучше сначала попробовать разобраться самостоятельно.

Динамическая отладка приложений

Runtime-логирование.Чтобы получить общую картину значений и состояний, которые принимает код в определённые моменты времени, в него добавляют вызовconsole.logс нужными аргументами на всех интересующих участках. Разумеется,console.log самый популярный вариант, но далеко не единственный. В отладке помогут и такие методы, какconsole.trace,console.assert,console.count,console.time.

Интерактивные средства отладки.Способ предполагает работу в отладчике(дебаггере). Современные браузеры и IDE уже содержат в себе отладчики, так называемые средства разработчика.

Локализация проблемы(разделяй и властвуй).Способ заключается в последовательном комментировании или удалении участков кода, пока проблема или ошибка не перестанут воспроизводиться. Популярной имплементацией является бинарный поиск: удалить половину кода и посмотреть, осталась ли ошибка, если да, то удалить половину оставшейся половины и так далее.git bisectиспользует бинарный поиск по истории коммитов, чтобы помочь разработчику найти коммит, в котором была добавлена ошибка.

Типовые ошибки и где они обитают

Ошибки в программе могут возникать на разных уровнях:

  • Лексическиеошибки неверно записанные идентификаторы, ключевые слова или операторы. Например, вызов метода.toLowercase()вместо.toLowerCase()или использование кириллической буквы свместо латинской(никогда так не делайте).

  • Синтаксическиеошибки неверно поставленные точки с запятой или лишние/недостающие фигурные скобки. Ошибки такого типа препятствуют корректной интерпретации кода, поэтомуон не может быть выполнен.

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

  • Логическиеошибкимогут быть любыми от неверного алгоритма бизнес-логики приложения и недостижимых участков кода до использования оператора присваивания=вместо оператора сравнения==. Такие ошибки сложнее всего обнаружить, потому что код может быть синтаксически корректным, выполняться без ошибок, но делать совсем не то, что нужно.

Обнаружение ошибок

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

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

Если страница отрисовалась, можно приступать к тестированию функциональности. Лексические и синтаксические ошибки легче всего обнаруживаются через консоль в средствах разработчика, поэтому держите её открытой. Чаще всего эти ошибки будут экземплярами классовSyntaxErrorилиTypeError, поэтому в консоли вы увидите что-то подобное:

Uncaught TypeError: Cannot read property 'x' of undefined

или

Uncaught SyntaxError: expected expression, got ';'

Поймать логическую ошибку сложнее. Если вы добавили новый функционал, лучше его протестировать, то есть, как минимум, выполнить те же действия, которые выполнит рядовой пользователь: понажимать на кнопочки, открыть нужные страницы и так далее. В процессе взаимодействия постоянно отслеживайте появление ошибок в консоли, а также соответствие интерфейса дизайну и требованиям. Любое отклонение от них(отрисовалось не то, не там, не отрисовалось вообще) это баг, если такое поведение не оговорено отдельно с менеджерами проекта или девлидом команды разработки.

Зачем нужны DevTools и как ими пользоваться

Клиентский JS-код интерпретируется ивыполняется вбраузерах, поэтому в них встроены инструменты для разработчиков (DevTools). Они помогают отслеживать иизучать параметры, характеризующие состояние веб-страницы в текущий момент или ранее. Также есть возможность приостанавливать ипродолжать выполнение кода, перемещаться понему имногое другое.К счастью для веб-разработчиков,DevTools современных браузеров(Chrome, Firefox и Safari)имеют схожую структуру и открываются одинаково. Поэтому даже если вы всю жизнь пользовались Chrome, открыв инструменты разработчика в Safari, сможете достаточно быстро освоиться.

Используемый стек технологий

Хотя HTML, CSS и JavaScript это Святая Троица веб-разработки, мало кто применяет чистыйJS для построения больших SPA-приложений. Библиотеки, фреймворки и утилиты привносят свои особенности вструктуру кода ипроекта вцелом.В нашей компании почти вся разработка ведется с использованиемReact, который собирается в единый JS-бандл с помощьюWebpack, и к этому, как правило, прикрученHot Module Reload. Далее всё будем рассматривать в контексте этого стека.

Начало работы

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

Сочетания клавиш:

  • Windows и Linux Ctrl+Shift+IилиF12.

  • macOS Cmd+Opt+I. Обратите внимание, что в Safari необходимо предварительно активировать инструменты разработчика. Подробнее об этом Enable Web Inspector.

Для отладки JavaScript-кода чаще всего будут полезны вкладкиConsole,SourcesиNetwork. Обратите внимание, что средства разработчиков могут включать не только собственные инструменты браузера, но и дополнительные инструменты из расширений. Так, на изображении ниже вкладкиComponentsиProfilerпринадлежат расширениюReact Developer Tools.

Инструменты разработчика в Chrome 86, открытые на вкладке ConsoleИнструменты разработчика в Chrome 86, открытые на вкладке Console

Изучаем вкладку Console

Консоль выполняет две большие задачи:

  1. Показывает сообщения разного уровня: ошибки, предупреждения, информацию общего характера.

  2. Выводит и выполняет JS-код, то есть работает в форматеREPL.

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

Как видно на скриншоте, там может быть много всего: браузерные предупреждения, информационные сообщенияотwebpack-dev-serverиhot-module-replacement, логи обращений к API(если вы настроили вывод их в консоль), ошибки сетевых соединений.Для упрощения восприятия информации полезно отсечь ненужные уровни логирования. Для этого раскройтеселектDefault levelsи выберите в нём только нужное. Например, можно оставить только ошибки или только предупреждения:

Изучаем вкладку Sources

ВкладкаSourcesобычно используется при отладке больших, сложных проектов. В браузерах Firefox и Safari аналогичная вкладка называетсяDebugger.С её помощью можно изучить те ресурсы(скрипты, изображения, стилевые файлы), к которым у страницы есть доступ. Как правило, этот доступ можно получить в результате загрузки ресурса по сети, однако некоторые инструменты, например Webpack, инжектят свои собственные ресурсы.

На скриншоте ниже вкладкаSourcesв Chrome 86. В левой части находится раздел выбора нужного ресурса для отображения, имеющий древовидную структуру. По центру окно просмотра выбранного ресурса, а справа инструменты отладки JS-скриптов.В нашем примере проект запущен локально черезwebpack-dev-serverи доступен по адресуhttp://localhost:8080:

Как видно на скриншоте, сейчас открыт файлapp.js, содержащий JS-бандл. Этот файл результат работы сборщика(Webpack), именно его скачивает браузер при открытии индексной HTML-страницы. Файл большой и искать что-то по нему трудно, поскольку в нём собраны все модули проекта, а сверху Webpack добавил свою обвязку. К счастью, при локальной разработке можно быстро и удобно просматривать компоненты.

Быстрый доступ к компонентам и модулям

В дереве ресурсов в левой части панелиSourcesприсутствует разделwebpack://. За счёт сорсмапов(sourcemaps, карт кода)этот раздел предоставляет доступ кисходныммодулям и компонентам проекта и фактически повторяет файловую структуру проекта так, как вы её видите у себя в IDE или редакторе.

Обратите внимание, что нет необходимости искать кусок, отвечающий за модульmain.jsx,в общем бандлеapp.js. Вместо этого можно сразу открыть компонентmain.jsxи просмотреть его содержимое в исходном виде,as is. Если в вашем проекте существуетвыделенный в отдельный файл модуль, но он нигде не подключается, то в структуре разделаwebpack://вы его не найдёте, поскольку сам Webpack о нём ничего не узнает, если не импортировать модуль.

Быстрый переход к модулю по имени файла

Поскольку структура больших проектов почти всегда бывает сложной и разветвлённой, поиск нужного модуля по дереву компонентов может быть утомительным. В этом случае на помощь приходит сочетание клавишCtrl+O(Ctrl+P) в Chrome / Firefox иCmd+Shift+Oв Safari. Нажатие клавиш открывает попап, в котором можно найти компонент по названию файла и быстро к нему перейти.

Изучаем вкладку Network

Все или почти все веб-приложения обращаются к внешним ресурсам по сети, то есть совершают сетевые запросы. Примеры таких запросов: получение статического файла(JS-скрипта, файла с CSS-стилями), обращение к backend-серверу через REST API.ВкладкаNetworkпозволяет получить достаточно полную информацию о том, какие сетевые запросы совершает страница в тот или иной момент времени.

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

Столбцы таблицы, кроме столбцаName, настраиваются:можно скрывать ненужные и добавлять дополнительные. Для настройки отображаемых столбцов необходимо кликнуть правой кнопкой мыши на шапке таблицы и отметить в списке нужные варианты.

Поскольку веб-страница может совершать большое количество запросов, разработчиков выручает функция фильтрации, которую предоставляет вкладкаNetwork. Очень удобным и, скорее всего, наиболее популярным является фильтр по типу ресурса(обведён красной рамкой). Например, на скриншоте выбрано отображение только XHR-запросов:

Зачастую страница обращается не только к собственным ресурсам, но и к сторонним, например к скриптам аналитики. Исключить отображение запросов к внешним ресурсам можно с помощью поляFilter, поддерживающего некоторые ключевые слова для фильтрации. Так, можно указатьdomain:yourdomain.comдля выборки запросов по доменному имени:

Больше ключевых слов для поляFilterв Google Chrome можно найти на страницеhttps://developers.google.com/web/tools/chrome-devtools/network/reference#filter-by-property.

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

РазделPreviewпоказывает тело ответа в человекочитаемом виде, что может быть важно при отладке запросов от клиента к серверу. На скриншоте ответ от сервера, полученный в форматеapplication/json представлен в виде объекта, поля которого можно раскрывать и изучать.

ЧекбоксыPreserve logs(в некоторых браузерах Persist logs)иDisable cacheтакже важны при отладке:

  • ЧекбоксPreserve logsсохраняет базовую информацию о запросах при перезагрузке страницы или при редиректе на другой сайт.

  • ЧекбоксDisable cacheотключает кэширование ресурсов, пока открыты средства разработчика. Чтобы получать актуальную версию запрашиваемых ресурсов в процессе разработки, рекомендуется всегда активировать эту опцию.

Дебажим ошибки из консоли

Рассмотрим такой пример:

class CategoryList extends React.Component { constructor(props) {   super(props);      this.state = {    categories: undefined, // <--- должно быть "categories: []"   }; }  mapCategoriesFromState() {   const mapped = this.state.categories.map(mapFn); // <--- вызываем метод ".map"    this.setState({    categories: mapped,   }); }  render() {   this.mapCategoriesFromState();   return 'Hello'; }}

Здесь встречается явная ошибка разработчик забыл,что не объявилcategoriesкак массив, и пытается вызвать метод.map.В консоли будет наблюдаться сообщение вида:

category-list.jsx:11 Uncaught TypeError: Cannot read property 'map' of undefined at CategoryList.mapCategoriesFromState (category-list.jsx:11) <--- ошибка здесь at CategoryList.render (category-list.jsx:19) at finishClassComponent (react-dom.development.js:14742) at updateClassComponent (react-dom.development.js:14697) at beginWork (react-dom.development.js:15645) at performUnitOfWork (react-dom.development.js:19313) at workLoop (react-dom.development.js:19353) at HTMLUnknownElement.callCallback (react-dom.development.js:150) at Object.invokeGuardedCallbackDev (react-dom.development.js:200)

Сообщение состоит из собственно текста ошибки (Uncaught TypeError: Cannot read property 'map' of undefined) и стектрейса, из которого хорошо видно, что ошибка произошла в методеmapCategoriesFromStateклассаCategoryListна 11 строке файлаcategory-list.jsx. Этого уже достаточно, чтобы открыть указанное место в коде и проанализировать, как так вышло.

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

The above error occurred in the <CategoryList> component: in CategoryList (created by Connect(CategoryList)) in Connect(CategoryList) (created by MainApp) in OfferProvider (created by Connect(OfferProvider)) in Connect(OfferProvider) (created by MainApp) in MainApp (created by Connect(MainApp)) in Connect(MainApp) (created by Context.Consumer) in Route (created by App) in Switch (created by App) in Router (created by BrowserRouter) in BrowserRouter (created by App) in Provider (created by App) in App (created by HotExportedApp) in AppContainer (created by HotExportedApp) in HotExportedApp

Дебажим проект с помощью отладчика

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

Что может отладчик в инструментах разработчика

Основные возможности отладчика:

  • приостановка выполнения кода;

  • перемещение по коду(пошаговое выполнение);

  • проверка значения переменных;

  • просмотр добавленных обработчиков событий(event listener handlers);

  • редактирование кода или значений переменных налету.

Конечно, это не весь список возможностей отладчика, но для большинства задач этого обычно хватает.

Почему не console.log

Недостатокconsole.logзаключается в узком поле зрения: вы увидите лишь то, что передадите в качестве аргумента. Когда нужно отслеживать сразу множество параметров или переменных, то придётся сначала добавить в код кучу вызововconsole.log, а потом каждый раз руками менять передаваемые аргументы, чтобы вывести в консоль что-то другое.

Идея отладки в том, чтобы найти ошибку в ситуации, когда до концанепонятно, что искать и где. Для этого используютсяточки останова(breakpoints, брейкпоинты) этоместо в коде, где отладчик автоматически приостановит выполнение JavaScript.

Отладчик браузера поддерживаетнесколько видов брейкпоинтов:

  • Брейкпоинт на строке кодасрабатывает, когда интерпретатор JS доходит до указанной строки.

  • Условный брейкпоинт на строке кодасрабатывает при указанном условии.

  • Брейкпоинт на DOM-узлесрабатывает при изменении этого узла.

  • Брейкпоинт на XHR-запросесрабатывает при определённом сетевом запросе.

  • Брейкпоинт на событиисрабатывает при его наступлении.

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

Большая часть процесса отладки заключается в следующем:

  1. Ставим брейкпоинты в нужных местах.

  2. Смотрим значение переменных или проверяем порядок выполнения кода.

  3. Перемещаемся по коду или ставим новые брейкпоинты и проверяем, какие данные содержит код в конкретный момент времени и как они используются.

Манипуляции с брейкпоинтами

Чтобы поставить брейкпоинт:

  • выберите нужный скрипт в дереве ресурсов в левой части панелиSources;

  • кликните левой кнопкой мыши по цифре, обозначающей номер строки, слева от кода.

Если кликнуть не левой, а правой кнопкой мыши, появится контекстное меню для выбора типа брейкпоинта: обычного, условного или точки логирования.

После этого на указанной строке создастся точка останова и цифра с номером строки подсветится синим цветом, а в правой части панели в спискеBreakpointsпоявится новая запись, указывающая на созданный брейкпоинт. Теперь, если обновить страницу, выполнение кода приостановится на указанной строке.

Действия, которые можно производить с брейкпоинтом после установки:

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

  • Временно отключить (игнорировать), сняв галочку напротив брейкпоинта в спискеBreakpointsв правой части.

  • Сменить тип, кликнув по нему правой кнопкой мыши и выбрав в контекстном меню пунктEdit breakpoint.

Перемещение по коду

Самая полезная функция отладчика пошаговая отладка. Эта функция даёт возможность выполнять код поодной строке зараз.

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

На скриншоте красной рамкой выделены кнопки-стрелки, которые позволяют перемещаться покоду:

  • КнопкаResume script execution.Название говорит за себя: код продолжит выполняться до следующей точки останова или пока не выполнятся все инструкции в скрипте.

  • Кнопка Step over next function call. При нажатии отладчик выполняет инструкцию на текущей строке и переходит на следующую. При этом, если на строке с брейкпоинтом был указан вызов функции, отладчик не будет заходить в неё.

  • Кнопка Step into the next function callпригодится, если текущая строка содержит вызов функции и нужно попасть внутрь этой функции.На скриншоте нажатие этой кнопки переведёт отладчик внутрь функцииthis.isUnkownCategory().

Коварный hot-loader

Если впроекте для режима разработки используется react-hot-loader, токнопкаStep into the next function callможет сработать нетак, как выожидаете. Поскольку react-hot-loader подменяет собой настоящий ReactDOM для адекватной работыhot reload, попытка зайти вметод React-компонента, если компонент объявлен ввиде класса, уведёт вас внутрь React, откуда потом невыбраться.

  • Кнопка Step out of current functionпоможет, если вы зашли в функцию, но поняли, что делать в ней нечего. Отладчик автоматически выполнитдальнейшие инструкциивнутри текущей функциии выйдет из неё.В примере ниже нажатие кнопки вернет отладчик обратно вcomponentDidMount:

КнопкиStep over, Step into, Step outприсутствуют в отладчиках Chrome, Firefox и Safari. Google добавил в Chrome четвёртую кнопкуStep. По функциональности она похожа на кнопкуStep into, разница лишь в том, как они обрабатывают выполнение асинхронных функций. Подробнее о различиях можно почитать вчейнджлоге Google.

Исследование кода

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

Обратите внимание, что панель Scope имеет несколько вкладок, которые показывают переменные из локальной области видимости(Local), области замыкания(Closure)и глобальной области видимости(Global). Значение переменных также можно поменять: дважды кликните по значению переменной в панелиScopeи введите новое значение.

Если React-компонент является текущим контекстом выполнения, на панелиScopeудобно отслеживать его текущее состояние и значение локальных переменных.На скриншоте видно, что в данный момент значениемthisявляется экземпляр классаMainLayout. И если необходимо изучить, какие пропсы переданы в компонент или что находится вthis.state, то это легко сделать черезScope.

Иногда нужно отладить функцию, которая вызывается много раз, но нужно поймать её в определённом состоянии. Для этого можно использоватьConditionalBreakpoint.Например, методthis.loadNextвызывается в разные моменты времени, но вместо того, чтобы много раз продолжать и останавливать выполнение кнопкойResume Script Execution, можно зацепиться за значение переменнойloadType. Тогда брейкпоинт сработает только в нужный момент времени.

Ответы на возможные вопросы

Мой код в отладчике выглядит совсем не так, как у меня в редакторе. Почему?

Чтобы код в отладчике выглядел так же, как в редакторе, нужно:

  • ничего с ним не делать(никаких транспиляций, сборщиков и прочего);

  • использовать сорсмапы.

Однако даже использование сорсмапов не гарантирует стопроцентного совпадения кода в отладчике с исходным, поскольку тот же Webpack предоставляет несколько возможных стилей для генерируемых карт кода. Подробнее о том, как выбранный вариант сорсмапов влияет на отображаемый результат, можно узнать вhttps://webpack.js.org/configuration/devtool/#devtool.

Cтраница бесконечно перезагружается или не реагирует. Как это остановить?

Иногда случается, что неудачное изменение кода и попадание в бесконечный цикл приводит к такому подвисанию страницы, что даже вкладку закрыть не получается, можно только остановить процесс браузера в целом. В этом случае может выручить диспетчер задач, встроенный непосредственно в браузер. В Chrome его можно открыть сочетанием клавишShift+Esc(на macOS доступ к диспетчеру можно получить через меню Window Task Manager). В Firefox также есть свой диспетчер задач (инструкцию по открытию можно найти настранице поддержки). Такой диспетчер может принудительно завершить процесс отдельной выбранной вкладки, если стандартные средства не помогают. Кроме того, в диспетчере можно отслеживать, сколько системных ресурсов(CPU, ОЗУ)потребляет вкладка с вашим приложением.

Однако не все браузеры обладают подобным функционалом. В качестве альтернативы, если в момент зависания страницы открыты средства разработчика, может спасти нажатие кнопкиPause script executionв разделе Sources(она жеResume script execution). Это остановит выполнение JavaScript, после чего можно будет закрыть вкладку или на месте посмотреть, почему цикл получился бесконечным.

Вижу в консоли"SyntaxError: unexpected token <"и ничего не работает. Откуда эта ошибка?

Такая ошибка обычно говорит о том, что JS-движок пытается интерпретировать HTML-разметку как код, что, конечно же, невозможно. В такой ситуации в инструментах разработчика откройте вкладкуNewtorkи посмотрите, нет ли сетевой ошибки загрузки JS-скриптов. Если что-то не так с загрузкой статики, вместо ответа может прийти страница ошибки NGINX, например так:

<html>  <head><title>404 Not Found</title></head>  <body bgcolor="white">    <center><h1>404 Not Found</h1></center>    <hr><center>nginx/1.14.0 (Ubuntu)</center>  </body></html>

Соответственно, в текстовом виде это будет обычная разметка, которая начинается с символа<.

Ставлю брейкпоинт, а он не ставится или перескакивает куда-то вниз. Что не так?

На это влияют сорсмапы. Даже если отладчик показывает вам что-то, что не отличается от кода в вашем редакторе, выполняет он всё равно сгенерированный, переработанный утилитами код. И чем сильнее разница между итоговым кодом и исходным, чем больше преобразований совершается, тем больше шансов, что будет попытка остановить код в невалидном месте(например, на закрывающей}). В этом случае можно попробовать поставить брейкпоинт парой строчек выше или ниже или изменить стиль сорсмапов, чтобы отображаемый код был ближе к фактическому.

Ещё один инструмент отладки

Количество ошибок в коде зависит от разных факторов: уровня разработчика, сложности используемых технологий, объёма кода. На мой взгляд, один из важных факторов обмен знаниями в проекте или команде. Разобрался сам, помоги коллегам все от этого только выиграют. Если что-то из этой статьи перекочует в ваши внутренние базы знаний или хотя бы вспомнится в подходящий момент отладки клиентского JS-приложения, то я буду считать задачу этого текста выполненной.

Успехов с дебагом!

Полезные ссылки

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru