Обработка исключений в JavaScript
Перед этой главой прочитайте Ошибки, исключения и отказоустойчивость — в частности чем ошибка отличается от исключения.
Исключение в JS — предсказуемое отклонение (нет файла, неверный аргумент), которое перехватывают и обрабатывают, чтобы продолжить сценарий.
Фатальный сбой — необработанное исключение или unhandledrejection, из‑за которых падает вкладка, скрипт или (в Node 15+) процесс.
Встроенные типы Error — в 241.
Синтаксис: try / catch / finally
JavaScript использует структурную обработку: блок try связывается с catch и опциональным finally.
function readConfig(path) {
let raw;
try {
raw = fs.readFileSync(path, 'utf8');
return JSON.parse(raw);
} catch (e) {
if (e instanceof SyntaxError) {
throw new Error(`Некорректный JSON в ${path}`, { cause: e });
}
throw e;
} finally {
// освобождение ресурсов, если появятся (дескрипторы, временные файлы)
}
}
| Конструкция | Назначение |
|---|---|
try | Код, где сбой возможен |
catch (e) | Обработчик; в TS предпочтительно unknown + сужение типа |
finally | Выполняется всегда (очистка) |
throw value | Прервать поток; для API лучше throw new Error(...) |
Раскрутка стека и поиск обработчика — в общей теории.
Интерактивное демо — сценарии на Python в компоненте ниже; в JS синтаксис
try/catch, но стек тот же.
throw и цепочка cause
Всегда бросайте экземпляры Error (или наследников), а не строки — так сохраняются stack и cause.
async function loadUser(id) {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
return await res.json();
} catch (e) {
throw new Error(`Не удалось загрузить пользователя ${id}`, { cause: e });
}
}
В логах и DevTools видна цепочка cause — не теряйте её при обёртке (см. типичные ошибки).
Синхронный код vs Promise и async/await
| Контекст | Как ловить |
|---|---|
| Синхронный | try/catch вокруг вызова |
async функция | try/catch вокруг await |
.then() | второй аргумент или .catch() |
Ошибка внутри колбэка then | превращается в rejected Promise |
// Правильно: await в try
async function save() {
try {
await db.insert(row);
} catch (e) {
logger.error(e);
throw e;
}
}
// Ошибка: забыли await — rejection уйдёт мимо try
async function broken() {
try {
db.insert(row); // Promise без await
} catch (e) {
/* сюда не попадём при reject */
}
}
Теория асинхронных сбоев — раздел 4.05, FAQ — 998.
unhandledrejection и глобальные обработчики
Необработанный rejected Promise в браузере → событие unhandledrejection. В Node — то же; на современных версиях необработанный rejection может завершить процесс.
// Браузер
window.addEventListener('unhandledrejection', (event) => {
reportToSentry(event.reason);
});
// Node
process.on('unhandledRejection', (reason) => {
console.error('Unhandled rejection:', reason);
});
Синхронные необработанные ошибки — window.onerror / process.on('uncaughtException') (последний шанс перед выходом). Подробнее — 111.
Express и границы API
В async маршрутах Express ошибки из await нужно передать в next(err) или обернуть в middleware — иначе rejection не попадёт в центральный обработчик. См. Express — middleware и ошибки.
На границе HTTP — единый формат ответа, без stack trace клиенту: обработка ошибок в API.
TypeScript
Сужение в catch: catch (e: unknown) и проверка instanceof Error. Доменные коды и Result — Обработка ошибок в TypeScript.
Связанные материалы
- Встроенные типы ошибок
- Ошибки и исключения (теория)
- Исключения в читаемом коде
- JavaScript — о разделе
Что запомнить
- Бросайте
Error, сохраняйтеcauseпри обёртке. - В
asyncкоде оборачивайтеawaitвtry/catch. - Следите за
unhandledrejectionв продакшене. - Типы встроенных ошибок — в 241; контракт API — отдельно от механизма
throw.