Перейти к основному содержимому

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

Ошибки в функциях можно генерировать (throw), перехватывать (try/catch/finally) и логировать (console.error). Для пошаговой отладки в браузере или Node используют debugger. Ниже — по каждому приёму краткое описание и типичное применение.


1. try / catch / finally

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

catch выполняется, если в try возникло исключение. В скобках удобно принимать объект ошибки (часто имя err или e) и по нему решать: залогировать, показать пользователю сообщение, пробросить дальше (throw err).

finally выполняется всегда — и после успешного try, и после catch. Удобен для действий вроде закрытия ресурсов или сброса флагов «загрузка», даже если в catch снова выброшена ошибка.

Синхронный код внутри функции обрабатывают именно так; для промисов и async/await правила те же по смыслу, но запись чуть другая — это будет отдельно в разделе Асинхронность.

function divide(a, b) {
try {
if (b === 0) {
throw new RangeError('Деление на ноль');
}
return a / b;
} catch (err) {
console.error(err.message);
return null;
} finally {
// например: очистка таймера, сброс UI-состояния
}
}

2. Что передавать в throw: Error и типы

throw может выбрасывать любое значение, но принято бросать экземпляры Error или его подклассов — тогда в catch есть message, name, часто stack.

  • new Error('текст') — общий случай.
  • TypeError — неверный тип аргумента или недопустимое использование значения.
  • RangeError — значение вне допустимого диапазона.
  • SyntaxError — обычно парсер; в своём коде редко.

Для библиотек и крупных модулей иногда заводят свой класс class ValidationError extends Error, чтобы в catch отличать «наши» ошибки от системных (err instanceof ValidationError).

function requirePositive(n) {
if (typeof n !== 'number' || n <= 0) {
throw new TypeError('Ожидается положительное число');
}
}

3. throw и console.error: в чём разница

throw прерывает текущий поток выполнения: дальше код в той же функции не пойдёт, пока исключение не поймают (try/catch) или не «вылетит» наружу.

console.error только выводит сообщение в консоль (часто с теком, если передан объект Error). Выполнение продолжается.

Используйте throw, когда ситуация нештатная и дальше логика без корректных данных смысла не имеет. console.error — для диагностики там, где программа может продолжить работу (например, не удалось залогировать необязательное событие, но основной сценарий возможен).

// throw — «стоп, без этого работать нельзя»
function loadConfig(path) {
if (!path) {
throw new Error('Путь к конфигу обязателен');
}
// ...
}

// console.error — «записали проблему, но идём дальше»
function saveDraft(data) {
try {
localStorage.setItem('draft', JSON.stringify(data));
} catch (err) {
console.error('Черновик не сохранён', err);
}
}

4. Ошибки в колбэках и «стиль Node»

В асинхронных API со старым стилем колбэка часто первый аргумент — err: если он не null/undefined, это ошибка; иначе во втором аргументе приходят данные. Так вызывающий код сам решает, что делать с ошибкой, без автоматического try/catch по всему стеку.

С промисами и async/await ошибки обычно обрабатывают через .catch() или try/catch вокруг await. Подробности — в разделе Асинхронность; здесь важно помнить: в колбэках ошибка часто передаётся явно, в async-функциях — удобнее перехват блоком try/catch.


5. Ранние проверки (guard clauses)

Вместо глубокой вложенности if удобно в начале функции проверять аргументы и при нарушении условий сразу return с безопасным значением или throw с понятным сообщением. Так проще читать код и предсказывать, где «сломается» выполнение.

function getItemLabel(item) {
if (item == null) {
throw new TypeError('item обязателен');
}
if (typeof item.label !== 'string') {
return '(без названия)';
}
return item.label.trim();
}

6. debugger

Инструкция debugger останавливает выполнение, если открыты инструменты разработчика (в браузере — DevTools). Удобно ставить перед подозрительной строкой вместо временного console.log, чтобы смотреть переменные и стек.

В продакшене такие строки обычно убирают или отключают сборкой: иначе у пользователя с открытой консолью выполнение может неожиданно «залипать» на паузе.

function tricky(x) {
debugger; // пауза здесь, пока отладчик открыт
return x * 2;
}

Дополнительно (документация)