Интервью-вопрос
Какие знаешь способы отслеживания и обработки ошибок
Нужно показать, что вы умеете не только ловить исключения, но и сохранять нормальный UX, видеть ошибки в production и не отправлять лишние данные в логи. Хороший ответ разделяет локальную обработку, React fallback, глобальный перехват и мониторинг.
- Добавлен
- Редакция
Подготовьте короткий ответ и пару деталей на случай уточняющих вопросов.
Мини-квиз
Проверка перед разбором
Несколько быстрых вопросов перед разбором. Так проще поймать места, которые только кажутся понятными.
Вопрос 1 из 50 правильно
Разбор
Разобраться, а не зазубрить
Дальше разбираем суть, типичные уточнения и места, где легко сказать лишнее или перепутать термины.
Базовая идея
В ответе лучше сразу разделить два слова: обработка и отслеживание. Обработка отвечает за то, что увидит пользователь прямо сейчас. Отслеживание отвечает за то, как команда узнает об ошибке после релиза.
Коротко можно сказать так:
Я стараюсь ловить ошибку как можно ближе к месту, где могу принять правильное решение. Если это запрос, обрабатываю статус и сетевые ошибки. Если это React-рендер, использую Error Boundary для fallback UI. Если ошибка не была поймана локально, глобальные обработчики и monitoring помогают не потерять сигнал в production.
Такой ответ показывает систему, а не просто список инструментов. Это звучит сильнее, чем перечисление try/catch, console.error и Sentry без контекста.
Уровни обработки
На практике фронтенд обычно использует несколько уровней защиты. Локальный уровень нужен там, где понятен сценарий: форма, загрузка списка, сохранение настроек, оплата. В этих местах вы можете показать сообщение, не потерять состояние и дать повторить действие.
Уровень UI нужен, чтобы приложение не оставалось в вечном loading или пустом экране. Для React это состояние ошибки в компоненте, fallback, Error Boundary для части дерева и аккуратный rollback при optimistic update.
Глобальный уровень нужен как последняя сетка безопасности. Он не делает сценарий удобным сам по себе, зато помогает заметить в production необработанные исключения, ошибки загрузки ресурсов или promise без catch.
Как выбрать место обработки ошибки
Обработайте ее как часть сценария: покажите сообщение, подсветите поле, дайте retry или альтернативное действие.Используйте try/catch или .catch, проверяйте response.ok, обновляйте состояние error и очищайте loading.Поставьте Error Boundary вокруг рискованной зоны, покажите fallback и отправьте детали в мониторинг.Ловите ее глобально через error и unhandledrejection, чтобы не потерять сигнал в production.Отправляйте ее в Sentry, Rollbar или свой collector с release, route, breadcrumbs и безопасным контекстом.Пример с запросом к API
Частая ловушка на интервью связана с fetch. Он делает reject при сетевой ошибке, отмене запроса или похожей проблеме транспорта. Но HTTP-ответ со статусом 404 или 500 обычно придет как обычный response, поэтому его нужно проверить явно.
Плохой пример:
async function loadProfile() {
const response = await fetch("/api/profile");
return response.json();
}Здесь ошибка сервера может попасть в код как будто это успешный ответ. Еще хуже, если UI уже очистил старые данные и остался пустым. Если такой вызов стоит в React-эффекте и параметр быстро меняется, старый ответ может перетереть новые данные.
Более безопасный вариант для функции загрузки:
async function loadProfile(profileId, { signal } = {}) {
const response = await fetch(`/api/profile/${encodeURIComponent(profileId)}`, { signal });
if (!response.ok) {
throw new Error(`Profile request failed: ${response.status}`);
}
return response.json();
}
async function showProfile(currentProfileId) {
setStatus("loading");
try {
const profile = await loadProfile(currentProfileId);
setProfile(profile);
setStatus("success");
} catch (error) {
setStatus("error");
reportError(error, { route: "/profile" });
}
}В компоненте с загрузкой по параметру добавьте отмену. Это защищает от race condition и обновления состояния после размонтирования.
useEffect(() => {
const controller = new AbortController();
setStatus("loading");
loadProfile(profileId, { signal: controller.signal })
.then((profile) => {
setProfile(profile);
setStatus("success");
})
.catch((error) => {
if (error.name === "AbortError") return;
setStatus("error");
reportError(error, { route: "/profile" });
});
return () => controller.abort();
}, [profileId]);Ошибку в UI лучше делать не только видимой, но и доступной. Например, сообщение о неудачной загрузке можно отдать через role="alert" или связать с полем формы через aria-describedby. Тогда пользователь клавиатуры или скринридера тоже поймет, что произошло.
- 1Показать loading и сохранить прежнее состояние UI
- 2Сделать запрос и проверить response.ok
- 3На ошибке показать понятное сообщение, доступное для скринридера, и retry
- 4Залогировать unexpected error с контекстом
- 5Всегда сбросить loading в finally
- 1Считать любой ответ успешным
- 2Сразу перетереть данные в UI
- 3Оставить пользователя без сообщения об ошибке
- 4Писать только console.error в production
- 5Забыть вернуть loading в нормальное состояние
React и Error Boundary
Error Boundary стоит упоминать аккуратно. Он полезен, когда часть интерфейса может упасть при рендере, но вы хотите сохранить остальное приложение живым. Например, можно обернуть виджет с графиком, сложный кабинет или область с данными от внешнего сервиса.
Минимальный пример:
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
reportError(error, { componentStack: errorInfo.componentStack });
}
render() {
if (this.state.hasError) {
return <p>Не удалось показать этот блок. Попробуйте обновить страницу.</p>;
}
return this.props.children;
}
}Важно сразу сказать ограничение. Error Boundary не ловит ошибку внутри обработчика клика, setTimeout или async-функции. Там нужна обычная обработка в самом сценарии.
Глобальное отслеживание
Глобальные обработчики нужны не для того, чтобы весь код можно было писать без проверок. Это последний уровень, который помогает не потерять необработанные ошибки.
window.addEventListener(
"error",
(event) => {
const target = event.target;
const isResourceError = target && target !== window;
reportError(event.error ?? new Error(String(event.message || "Resource load error")), {
type: isResourceError ? "resource-error" : "window-error",
source: isResourceError ? target.src || target.href : event.filename,
line: event.lineno,
});
},
true
);
window.addEventListener("unhandledrejection", (event) => {
reportError(event.reason, {
type: "unhandledrejection",
});
});Третий аргумент true нужен, если вы хотите поймать ошибки загрузки скриптов, картинок или CSS в фазе capture. Но даже такой код не чинит экран пользователя. Он только отправляет сигнал команде.
В продакшене важно добавить release, sourcemaps, route, breadcrumbs и безопасный user id. Без версии релиза и sourcemaps stack trace из минифицированного бандла часто мало помогает. Но не отправляйте токены, cookies, пароли, содержимое форм и полный payload запроса.
Что сказать на интервью
Хороший ответ можно собрать в 4 шага.
- Сначала назвать локальную обработку:
try/catch,.catch, проверка статуса ответа, состояние ошибки в UI. - Затем React-уровень: Error Boundary для ошибок рендера и fallback UI.
- Потом глобальный уровень:
errorиunhandledrejectionкак последняя сетка безопасности. - В конце monitoring: Sentry, Rollbar или свой collector с фильтрацией данных и контекстом релиза.
Если хотите звучать практично, добавьте мысль про пользователя. Ошибка должна быть не только записана в лог, но и превращена в понятное состояние интерфейса. Это сразу отделяет зрелый frontend-подход от простого перечисления API.
Частые ошибки
Где обычно ошибаются
Проверьте формулировки, которые звучат уверенно, но на интервью быстро выдают пробелы.
- 1
Подменять обработку ошибки логированием
console.errorили отправка события в Sentry не помогают пользователю продолжить сценарий. Нужен UI-ответ: fallback, сообщение, повтор действия, сохранение введенных данных или откат optimistic update. На интервью лучше сказать, что логирование и UX-обработка решают разные задачи. - 2
Ждать, что fetch бросит ошибку на 500
fetchне делает reject для обычных HTTP-ошибок. Если не проверитьresponse.ok, можно показать пользователю некорректные данные или сломать парсинг ответа. Безопаснее явно обрабатывать статус и отдельно ловить сетевые ошибки. - 3
Использовать Error Boundary как универсальную защиту
Error Boundary не ловит ошибки вsetTimeout, обработчиках клика и async-функциях. Если сказать, что он ловит все, это легко проверят уточняющим вопросом. Правильнее описывать его как защиту от ошибок рендера внутри части React-дерева. - 4
Отправлять в мониторинг лишние данные
В error-report часто случайно попадают токены, email, содержимое форм и полный request body. Это риск безопасности и приватности. Перед отправкой нужно фильтровать данные и оставлять только контекст, который помогает воспроизвести проблему. - 5
Не различать expected и unexpected ошибки
Неверный пароль, пустая корзина или 404 для удаленной сущности часто являются ожидаемым состоянием продукта. TypeError в рендере или падение парсинга JSON уже ближе к дефекту. Если все отправлять как критические ошибки, мониторинг быстро превращается в шум. - 6
Забывать отмену запроса при смене экрана
Если пользователь быстро меняет фильтр, карточку или маршрут, старый ответ может прийти позже нового и перетереть актуальный UI. В React это часто чинят черезAbortController, cleanup вuseEffectили проверку актуального request id.
Follow-up
Что могут спросить дальше
Короткие ответы на вопросы, которыми проверяют практическое понимание обработки ошибок во фронтенде.
Живые ответы
Видео с похожим вопросом
Если найдем публичные интервью с таким вопросом, добавим их сюда. Их удобно смотреть после теории, чтобы свериться с живыми ответами.
Пока видео нет. Когда появятся подходящие публичные интервью, добавим их в этот блок, чтобы можно было сравнить разбор с тем, как отвечают реальные кандидаты.
Для чего нужен Storybook 😎
Storybook нужен для разработки, проверки и документации UI-компонентов в изоляции. Разбираем, как объяснить его пользу на интервью и не свести ответ к простой галерее кнопок.
Что такое end to end тесты 😎
E2E тесты проверяют полный пользовательский сценарий через интерфейс и реальные интеграции. На странице разбираем, где они полезны, чем отличаются от unit и integration тестов и как не сделать их хрупкими.