Работаем с исключениями в JavaScript | OTUS

Работаем с исключениями в JavaScript

Хорошо ли будет, если при вводе неверных данных в форму возникнет внутренняя ошибка сервера «500»? Да, когда происходит что-либо непредвиденное, нас учат генерировать исключения, однако практика показывает, что это не самый лучший метод обработки ошибок. Давайте разберемся, почему. Заодно и поговорим, как управлять потоком выполнения с исключениями.

Исключения нарушают безопасность типов

Это так, и это происходит даже в статически типизированных языках. Дело в том, что согласно своей сигнатуре, функция fetchUser(id: number): User обязана вернуть пользователя. И ничего в сигнатуре функции не говорит нам о том, что если пользователь найден не будет, будет сгенерировано исключение. А если исключение ожидается, то более подходящей сигнатурой будет: fetchUser(...): User|throws UserNotFoundError. Но такой синтаксис уже недопустим, причем вне зависимости от языка.

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

Исключения становятся причиной нарушения композиции функций

Исключения делают практически невозможным применение композиции функций. В примере ниже сервер вернет нам внутреннюю ошибку («500»), если одна из публикаций не найдена в блоге.

Screenshot_1-1801-3d2e1b.png

Но что, если одно из сообщений будет удалено, а пользователь будет пытается получить доступ к сообщению из-за какого-нибудь бага? Все это существенно ухудшит User Experience.

Кортежи — альтернативный способ обработки ошибок

Один из способов обработки ошибок заключается в возврате кортежа, который содержит результат и ошибку, вместо генерирования исключения. Язык программирования JavaScript кортежи не поддерживает, однако их можно легко эмулировать, применяя для этого массив из 2-х значений в форме [error, result]. Кстати говоря, это еще и стандартный метод обработки ошибок в Go:

Screenshot_2-1801-27aa0a.png

В некоторых случаях исключения хороши

Нельзя не сказать, что исключения продолжают занимать определенное место в вашей кодовой базе. Спросите себя, желаете ли вы, чтобы ваша программа завершилась аварийно? Ведь любое брошенное исключение способно «уронить» весь процесс. И пусть даже вы предполагаете, что пристально изучили все потенциальные пограничные случаи, все же стоит понимать, что исключения небезопасны и станут причиной аварийного завершения программы в будущем. Следует выбрасывать исключения лишь тогда, когда вы абсолютно уверены и имеете намерение вывести программу из строя. К примеру, если речь идет об ошибке разработчика либо о сбое соединения с БД.

Собственно говоря, сам термин «исключение» говорит сам за себя и предполагает исключительные случаи применения, когда у программы попросту отсутствует иной выбор, кроме аварийного завершения. Что бы кто не говорил, бросать и перехватывать исключения -- вряд ли хороший способ контроля потока выполнения. Именно поэтому прибегать к выбрасыванию исключений надо лишь в случае неисправимых ошибок. Кстати говоря, неверный пользовательский ввод, о котором мы говорили в самом начале статьи, к таковым ошибкам не относится.

Избегайте перехвата исключения — позвольте коду завершиться аварийно

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

Единственное исключение из вышеописанного правила — использование сторонних API. И даже в этом случае лучше применять вспомогательную функцию, оборачивающую основную функцию и возвращающую кортеж [error, result]. В частности, для этого можно использовать такие инструменты, как, например, Saferr.

Стоит в очередной раз спросить себя — а кто вообще несет ответственность за ошибку? Пользователь? Тогда ошибку надо обработать изящно. То есть пользователю лучше показать красивое сообщение, а не внутреннюю ошибку «500».

Что касается статического анализатора ESLint, то в нем отсутствует правило no-try-catch. При этом его ближайший сосед — no-throw.

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

Предлагаемая конфигурация ESLint:

Screenshot_3-1801-1a2bfe.png

Источник

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться
Популярное
Сегодня тут пусто