
Чтобы показать понятное сообщение, сначала определите источник сбоя: исключение в коде, ошибочный ответ сервера или проблему сети. Затем сопоставьте причину с безопасным текстом для пользователя, сохраните технические подробности отдельно и подготовьте подходящее действие: повторить запрос, исправить данные или обратиться в поддержку.
Что проверить перед показом ошибки пользователю
- Понятно ли, какое действие пользователя не удалось выполнить.
- Можно ли сообщить о проблеме без раскрытия текста исключения, адресов серверов и других внутренних данных.
- Нужен ли пользователю следующий шаг или ошибку можно обработать без уведомления.
- Не потерял ли пользователь введённые данные из-за сбоя.
- Есть ли в журнале приложения технические сведения, которые помогут разобраться с причиной.
Откуда приходит ошибка: исключение, ответ сервера или сбой сети
Разделение по источнику помогает выбрать правильный текст и действие. Такой подход подходит для форм, загрузки данных и других операций, где результат важен пользователю. Для фонового сбоя, который не влияет на работу интерфейса, отдельное сообщение может быть лишним.
- Исключение: ошибка возникла при выполнении кода, например из-за неверного преобразования данных или сбоя в сторонней библиотеке.
- Ответ сервера: запрос дошёл до сервера, но сервер вернул ошибку или сообщил, что данные нужно исправить.
- Сбой сети: приложение не смогло получить ответ. Причиной могут быть потеря соединения, тайм-аут или блокировка запроса.
В обработке ошибок в JavaScript важно различать ошибку выполнения и неуспешный HTTP-ответ: fetch обычно не отклоняет промис только потому, что сервер вернул статус ошибки. Статус нужно проверить отдельно через response.ok.
Как отделить технические детали от понятного сообщения
Для работы понадобятся доступ к коду запроса и обработчика формы, перечень ожидаемых ответов сервера и место для записи технических подробностей. Полезно заранее определить, какие ошибки требуют реакции пользователя, а какие можно обработать в фоне.
Не показывайте пользователю напрямую error.message или тело ответа сервера: там могут оказаться внутренние детали. Вместо этого сопоставляйте известные причины с короткими сообщениями, например "Не удалось сохранить изменения. Попробуйте ещё раз" или "Проверьте адрес электронной почты".
function getUserMessage(error) {
if (error?.kind === "network") {
return "Не удалось связаться с сервером. Проверьте соединение и попробуйте ещё раз.";
}
if (error?.kind === "validation") {
return "Проверьте введённые данные.";
}
return "Не удалось выполнить действие. Попробуйте позже.";
}
Техническую информацию можно записать отдельно, не выводя её в интерфейс:
try {
await saveChanges();
} catch (error) {
logger.error("Не удалось сохранить изменения", error);
showMessage(getUserMessage(error));
}
Какие состояния интерфейса подготовить для неудачного запроса
Перед изменением интерфейса проверьте подготовку:
- Определите, какой элемент показывает результат операции: область формы, уведомление или блок загрузки.
- Продумайте, как сохранить введённые данные после неудачи.
- Решите, какие ошибки требуют явного сообщения, а какие можно только записать в журнал.
- Уточните, какое действие доступно пользователю после каждой ошибки.
Затем настройте обработку по шагам:
-
Покажите состояние ожидания.
Пока запрос выполняется, дайте понять, что действие принято, и временно предотвратите случайную повторную отправку. -
Проверьте результат ответа.
После получения ответа проверьтеresponse.okи обработайте ожидаемые статусы, например ошибку проверки данных.- Для исправляемых данных покажите, какое поле нужно проверить.
- Для недоступности сервера предложите повторить действие позже.
-
Поймайте сбой запроса.
Используйтеtry/catch, чтобы обработать исключение или ошибку сети и не оставлять интерфейс в состоянии ожидания. -
Покажите безопасный текст.
Подберите сообщение по типу ошибки, не выводя внутренний текст исключения или необработанный ответ сервера. -
Верните интерфейс в рабочее состояние.
Снимите индикатор загрузки, сохраните введённые данные и оставьте доступным подходящий следующий шаг.
async function submitForm(data) {
setLoading(true);
try {
const response = await fetch("/api/profile", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
if (!response.ok) {
if (response.status === 400) {
showMessage("Проверьте введённые данные.");
return;
}
throw new Error("Request failed");
}
showMessage("Изменения сохранены.");
} catch (error) {
logger.error("Ошибка при сохранении профиля", error);
showMessage("Не удалось сохранить изменения. Попробуйте ещё раз.");
} finally {
setLoading(false);
}
}
Такой шаблон показывает, как обработать ошибки в JavaScript, сохраняя разделение между сообщением для интерфейса и технической записью. Если запрос отменён намеренно, не показывайте сообщение о сбое, если отмена не требует внимания пользователя.
Как обработать ошибки в async/await и цепочках промисов
JavaScript try catch обработка ошибок сработает для исключений внутри соответствующего блока и для отклонённых промисов, если перед ними стоит await. В цепочке промисов используйте .catch() или возвращайте ошибку дальше - не оставляйте отклонённый промис без обработчика.
- Проверяется ли
response.okпосле вызоваfetch. - Есть ли обработчик для каждого промиса, который может завершиться ошибкой.
- Не проглатывается ли ошибка без сообщения или записи в журнал.
- Снимается ли состояние загрузки в
finally. - Не отображается ли пользователю необработанный
error.message. - Сохраняются ли введённые данные после неудачной отправки.
- Обрабатываются ли отмена запроса и другие ожидаемые сценарии отдельно от неожиданных сбоев.
В обработчике промиса сохраняйте тот же принцип:
fetch("/api/items")
.then((response) => {
if (!response.ok) {
throw new Error("Request failed");
}
return response.json();
})
.then((items) => renderItems(items))
.catch((error) => {
logger.error("Не удалось загрузить список", error);
showMessage("Не удалось загрузить список. Попробуйте позже.");
});
Если пользователь отменил запрос, не обязательно показывать уведомление: достаточно вернуть интерфейс в ожидаемое состояние. Ошибку отмены не следует смешивать с сетевым сбоем.
Когда повторять запрос, а когда предложить другое действие
- Не запускайте автоматические повторы при ошибке проверки данных: предложите исправить поля.
- Не повторяйте без ограничений запрос, который снова и снова завершается ошибкой.
- Для временного сетевого сбоя предложите пользователю повторить действие, если его последствия понятны.
- Перед повторной отправкой операции, которая может создать дубликат, проверьте, поддерживает ли сервер безопасное повторение.
- Не повторяйте действие после отмены пользователем, если он не запросил его снова.
- Если повтор не поможет, предложите альтернативу: сохранить черновик, проверить данные или обратиться в поддержку.
Сообщение должно описывать конкретный следующий шаг. Например: "Не удалось загрузить список. Проверьте соединение и повторите попытку" информативнее, чем "Ошибка".
Как проверить сообщения на понятность и безопасность
Проверяйте формулировки на реальных сценариях: можно ли понять, что произошло, что сохранилось и как продолжить. Для проверки подойдут такие варианты:
- Текст рядом с полем. Уместен для ошибок ввода: укажите, что проверить именно в этом поле.
- Уведомление в интерфейсе. Подходит для сбоя действия, если пользователю нужно быстро увидеть сообщение и выбрать следующий шаг.
- Незаметная обработка. Используйте для ожидаемых фоновых событий, которые не требуют внимания; технический сбой при этом можно записать в журнал.
- Обращение в поддержку. Предложите этот вариант, если пользователь не может самостоятельно устранить проблему; не включайте в сообщение секреты или внутренние данные.
Чтобы вывести сообщение об ошибке пользователю JavaScript-приложения безопасно, используйте текст из заранее подготовленных вариантов и выводите его как текст, а не как HTML-разметку. Это снижает риск случайно отобразить недоверенное содержимое ответа сервера как разметку. Проверяйте сообщения на понятность и для случаев, когда запрос завершился успешно, но данные требуют внимания.
Разбор неоднозначных ситуаций при показе ошибок
Нужно ли показывать пользователю текст исключения?
Как правило, нет: исключение может содержать технические подробности, непонятные пользователю или нежелательные для публикации. Запишите его в журнал, а в интерфейсе покажите безопасное сообщение.
Почему fetch не попадает в catch при ответе с ошибкой?
Потому что неуспешный HTTP-статус сам по себе обычно не отклоняет промис fetch. Проверяйте response.ok и обрабатывайте статус отдельно.
Когда сетевой сбой можно не показывать?
Если он не влияет на текущую задачу и не требует решения пользователя, отдельное уведомление может быть лишним. Если действие не выполнено или данные недоступны, сообщите об этом и предложите следующий шаг.
Можно ли показать ответ сервера целиком?
Не следует выводить необработанный ответ: в нём могут быть внутренние сведения или текст, не предназначенный для интерфейса. Преобразуйте известные варианты ответа в понятные сообщения.
Что делать, если запрос отменён?
Если пользователь отменил операцию, обычно достаточно прекратить загрузку и вернуть интерфейс в рабочее состояние. Не сообщайте об отмене как о неожиданной ошибке.
Нужно ли автоматически повторять неудачный запрос?
Автоматический повтор уместен только для подходящих временных сбоев и при контролируемом числе попыток. Для действий, которые могут создать дубликат или изменить данные повторяйте запрос только при безопасной поддержке такого сценария.