try/catch и Error #
Ошибка в JavaScript прерывает нормальный поток выполнения. Конструкция try/catch/finally перехватывает исключение, даёт обработать его и при необходимости гарантировать завершающий код в finally.
try, catch, finally #
function parseQuantity(raw) {
try {
const value = Number(raw)
if (!Number.isInteger(value) || value < 1) {
throw new Error('Количество должно быть целым числом ≥ 1')
}
return value
} catch (err) {
console.error('Некорректный ввод:', err.message)
return 1
} finally {
// выполнится всегда — и при успехе, и при throw
}
}
parseQuantity('3') // 3
parseQuantity('0.5') // 1, в консоли сообщение об ошибке
try— блок, где ошибка может возникнуть.catch (err)— обработчик;errобычно экземплярErrorили его подкласса.finally— код, который выполняется послеtry/catchнезависимо от исхода (кроме фатальных сбоев процесса).
return внутри try или catch откладывает выполнение finally до выхода из функции, но finally всё равно отработает перед фактическим возвратом.
throw #
Ключевое слово throw создаёт исключение. Можно бросать любое значение, но на практике используют Error и наследников — у них есть message и stack:
function applyCoupon(cart, code) {
if (!cart.items.length) {
throw new Error('Корзина пуста')
}
if (code !== 'JSFLOW10') {
throw new Error('Промокод не найден')
}
return cart.total * 0.9
}
Не перехваченное исключение «всплывает» по стеку вызовов, пока не найдётся подходящий catch или процесс не завершится с ошибкой.
Объект Error #
Базовый конструктор:
const err = new Error('Сеть недоступна')
err.name // "Error"
err.message // "Сеть недоступна"
err.stack // строка со стеком вызовов (формат зависит от движка)
Встроенные подтипы (неполный список):
| Класс | Типичный случай |
|---|---|
SyntaxError | неверный синтаксис при eval, JSON.parse |
TypeError | вызов не-функции, чтение свойства у null |
RangeError | значение вне допустимого диапазона |
ReferenceError | обращение к необъявленной переменной |
JSON.parse('{ broken') // SyntaxError
null.trim() // TypeError
Пользовательские ошибки #
Для различения сценариев в catch удобны собственные классы:
class CheckoutError extends Error {
constructor(message, code) {
super(message)
this.name = 'CheckoutError'
this.code = code
}
}
function reserveStock(sku, qty) {
if (qty > 50) {
throw new CheckoutError('Превышен лимит на позицию', 'STOCK_LIMIT')
}
}
try {
reserveStock('hoodie-xl', 60)
} catch (err) {
if (err instanceof CheckoutError && err.code === 'STOCK_LIMIT') {
// показать пользователю понятное сообщение
} else {
throw err // неизвестная ошибка — пробрасываем дальше
}
}
Наследование от Error сохраняет stack и совместимость с instanceof. Поле code (или cause в современных движках) помогает маршрутизировать обработку без разбора текста message.
Ошибки и асинхронный код #
try/catch вокруг колбэка не перехватит ошибку, выброшенную внутри колбэка, вызванного позже:
function loadPrice(sku, onDone) {
setTimeout(() => {
throw new Error('Таймаут каталога') // не попадёт в внешний try/catch
}, 0)
}
try {
loadPrice('mug-01', () => {})
} catch (err) {
// сюда не дойдёт
}
Для отложенного кода ошибки передают через колбэк (onError), промис (.catch) или async/await — эти темы в следующих статьях раздела.
Итог #
try/catch/finallyобрабатывает синхронные исключения в одном стеке вызовов.throwпрерывает выполнение; предпочтительно бросатьErrorи подклассы.- Пользовательские ошибки упрощают ветвление в
catchпо типу или коду. - Асинхронные ошибки требуют отдельного канала доставки — не полагайтесь на внешний
try/catchвокруг отложенного вызова.