Каждый разработчик хотя бы раз ловил себя на мысли: «Почему это вообще работает?» или «Что за черт, почему упало?». Ошибки в JavaScript — как внезапный дождь: вроде бы предсказуемо, но всегда некстати. Но если вы научитесь их обрабатывать, то сможете превратить хаос в порядок. В этой статье я расскажу, как сделать ваши приложения устойчивыми к сбоям, даже если что-то идет не по плану.
Почему ошибки — это не приговор, а часть жизни
Давайте сразу договоримся: ошибки в коде — это нормально. Даже у топ-разработчиков они случаются. Главное — не избегать их, а уметь вовремя поймать и корректно отреагировать. В JavaScript есть несколько способов обработки ошибок: от простого try...catch до использования промисов и асинхронных функций. Каждый из них — как инструмент в ящике: нужен для своей задачи.
Представьте, что вы готовите ужин. Если вы пересолили суп — это ошибка. Но вы же не выбрасываете кастрюлю, а просто добавляете воды. Так и в программировании: ошибка — это сигнал, что что-то пошло не так, и ваша задача — понять, что именно, и исправить ситуацию.
Основы: try...catch, throw и finally
Начнем с классики — конструкции try...catch. Это как страховка: вы пытаетесь выполнить код, и если что-то падает, вы ловите ошибку и делаете что-то разумное. Например:
try {
// Пытаемся выполнить опасный код
let data = JSON.parse('{"name": "WNDER"}');
console.log(data.name);
} catch (error) {
// Ловим ошибку и выводим сообщение
console.error('Что-то пошло не так:', error.message);
} finally {
// Этот блок выполнится всегда, даже если ошибки не было
console.log('Операция завершена');
}
Здесь try — это попытка, catch — обработка ошибки, а finally — то, что происходит в любом случае. Это как в жизни: вы пытаетесь открыть дверь, если ключ не подходит — вы ругаетесь (catch), но в итоге все равно идете к соседу за запасным (finally).
А еще есть оператор throw — он позволяет вам самим создавать ошибки. Например, если пользователь ввел некорректные данные:
function divide(a, b) {
if (b === 0) {
throw new Error('Деление на ноль запрещено');
}
return a / b;
}
try {
console.log(divide(10, 0));
} catch (error) {
console.log('Ошибка:', error.message);
}
Тут мы сами говорим: «Стоп, так нельзя». Это помогает избежать непредсказуемого поведения программы.
Асинхронные ошибки: работа с промисами и async/await
Современный JavaScript — это мир асинхронности. Запросы к серверу, чтение файлов, таймеры — все это работает не сразу, а через какое-то время. И тут ошибки прячутся по-другому. Если в синхронном коде мы просто оборачиваем все в try...catch, то с промисами нужно быть внимательнее.
Для промисов есть метод .catch(). Например:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Ошибка запроса:', error));
А если вы используете async/await, то можно снова вернуться к привычному try...catch:
async function getData() {
try {
let response = await fetch('https://api.example.com/data');
let data = await response.json();
console.log(data);
} catch (error) {
console.error('Ошибка:', error);
}
}
Обратите внимание: await работает только внутри async-функций. И если вы забудете обернуть вызов в try...catch, ошибка может «упасть» молча, и вы будете долго искать причину.
Продвинутые техники: кастомные ошибки и глобальный перехват
Иногда стандартных ошибок мало. Например, вы хотите различать ошибки валидации и ошибки сети. Для этого можно создавать свои классы ошибок:
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = 'ValidationError';
}
}
function validateUser(user) {
if (!user.name) {
throw new ValidationError('Имя обязательно');
}
}
try {
validateUser({});
} catch (error) {
if (error instanceof ValidationError) {
console.log('Проблема с данными:', error.message);
} else {
console.log('Неизвестная ошибка:', error);
}
}
Это как разные типы сигналов на приборной панели: красный — критично, желтый — предупреждение. Так вы сразу понимаете, что случилось.
Еще есть глобальный перехват ошибок — window.onerror и process.on('uncaughtException') для Node.js. Но это уже для крайних случаев, когда ошибка происходит вне вашего контроля, например, в сторонней библиотеке.
Практические советы и лайфхаки
Теперь давайте подведем итоги и дадим несколько советов, которые пригодятся в реальной работе.
Вот еще несколько лайфхаков:
- Используйте
console.errorвместоconsole.logдля ошибок — так их проще найти в логах. - Логируйте ошибки в специальный сервис (например, Sentry), чтобы знать о проблемах до того, как о них сообщат пользователи.
- Не оставляйте пустые
catchблоки — всегда хотя бы выводите ошибку в консоль. - Для асинхронных функций используйте
try...catchвнутри, а не снаружи — так вы не пропустите ошибку.
Также полезно знать, какие ошибки бывают. Вот небольшая таблица:
| Тип ошибки | Когда возникает | Пример |
|---|---|---|
| SyntaxError | Синтаксическая ошибка в коде | Пропущена скобка |
| TypeError | Неверный тип данных | Обращение к свойству undefined |
| ReferenceError | Несуществующая переменная | Использование переменной до ее объявления |
| RangeError | Число вне допустимого диапазона | Массив с отрицательной длиной |
| URIError | Некорректный URI | Неправильный encodeURI |
И помните: ошибки — это не враги, а подсказки. Они говорят вам, где нужно быть внимательнее. Если вы научитесь их слушать, ваш код станет крепче, а пользователи — счастливее.
Итоги
Итак, мы разобрали, как обрабатывать ошибки в JavaScript. Главное — не игнорировать их, а использовать все доступные инструменты: try...catch, throw, промисы и async/await. Не забывайте про кастомные ошибки и глобальный перехват — они помогают сделать код понятнее и устойчивее.
В итоге вы получите приложение, которое не развалится при первой же проблеме, а аккуратно сообщит о ней и продолжит работать. Это и есть признак профессионализма — не писать код без ошибок, а уметь с ними справляться.
Студия WNDER



