[Разработка веб-сайтов, JavaScript, Программирование, Отладка] Обработка ошибок в JavaScript

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
07-Сен-2020 14:32

Привет, Хабр!Тема обработки ошибок в 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? Ниже несколько примеров.Всегда оборачивайте асинхронный код в try…catch, а также вызовы сторонних библиотек.Вот пример:
// ...
const middlewareRequest = async (req) => {
  try {
    const { data } = await axios.get(req);
    return data;
  } catch (err) {
    throw new Error(err);
  }
}
// ...
Опытный архитектор может заметить, что если оборачивать все асинхронные конструкции в try…catch, то это сродни «аду коллбэков», поэтому придерживайтесь методологии 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 компании «Рексофт».
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_razrabotka_vebsajtov (Разработка веб-сайтов), #_javascript, #_programmirovanie (Программирование), #_otladka (Отладка), #_javascript, #_oshibki_v_kode (ошибки в коде), #_otladka_javascript (отладка javascript), #_sovety_programmistam (советы программистам), #_razrabotka_vebsajtov (
Разработка веб-сайтов
)
, #_javascript, #_programmirovanie (
Программирование
)
, #_otladka (
Отладка
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 17:48
Часовой пояс: UTC + 5