try...catch...finally
try...catch...finally— конструкция обработки ошибок: блокtryвыполняет код,catchперехватывает выброшенное исключение,finallyвыполняется всегда — независимо от результата.
Зачем нужно
Без обработки ошибок любое необработанное исключение прерывает выполнение скрипта. try...catch позволяет продолжить работу программы при ошибке, вывести понятное сообщение пользователю или выполнить очистку ресурсов. finally гарантирует завершающие действия (закрытие соединения, скрытие спиннера) вне зависимости от исхода.
Где используется
- Обработка ошибок при работе с API (
fetch, JSON-парсинг) - Работа с
localStorage, файлами, внешними зависимостями - Гарантированная очистка ресурсов в
finally - Валидация и выброс кастомных ошибок через
throw
Синтаксис и поведение
try {
// Код, который может выбросить ошибку
const data = JSON.parse('невалидный JSON'); // SyntaxError
} catch (error) {
// error — объект Error
console.error(error.name); // "SyntaxError"
console.error(error.message); // "Unexpected token..."
console.error(error.stack); // стек вызовов
} finally {
// Выполняется всегда: и при ошибке, и без неё
console.log('Завершено');
}
Примеры
Работа с fetch
async function fetchUser(id) {
let spinner;
try {
spinner = showSpinner;
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error('Ошибка загрузки пользователя:', error.message);
showError('Не удалось загрузить данные');
return null;
} finally {
hideSpinner(spinner); // выполнится даже при ошибке
}
}
Кастомные ошибки через throw
class ValidationError extends Error {
constructor(field, message) {
super(message);
this.name = 'ValidationError';
this.field = field;
}
}
function validateAge(age) {
if (typeof age !== 'number') throw new TypeError('Возраст должен быть числом');
if (age < 0 || age > 150) throw new ValidationError('age', 'Некорректный возраст');
return true;
}
try {
validateAge(-5);
} catch (error) {
if (error instanceof ValidationError) {
console.log(`Поле ${error.field}: ${error.message}`);
} else if (error instanceof TypeError) {
console.log('Ошибка типа:', error.message);
} else {
throw error; // пробросить неожиданные ошибки
}
}
JSON.parse с fallback
function safeParseJson(str, fallback = null) {
try {
return JSON.parse(str);
} catch {
// catch без переменной (ES2019+)
return fallback;
}
}
const data = safeParseJson(localStorage.getItem('config'), {});
finally для очистки
function openConnection() { /* ... */ }
function closeConnection(conn) { /* ... */ }
async function doWork() {
const conn = openConnection;
try {
await processData(conn);
} finally {
closeConnection(conn); // закроем соединение в любом случае
}
}
Частые ошибки
- Поглощение ошибок без логирования — пустой
catchскрывает проблему; всегда логируйте или перебрасывайте ошибки. returnвfinallyперекрываетreturnвtry— если вfinallyестьreturn, он всегда побеждает; избегайтеreturnвfinally.try...catchне ловит асинхронные ошибки — ошибки вsetTimeoutили промисах безawaitне перехватываются синхроннымcatch; используйтеasync/awaitили.catch.