Ошибки async-функции: где действительно работает try/catch
Где поставить await, как обработать отказ Fetch и вернуть кнопку в рабочее состояние после ошибки.
- awaitДожидаемся Promise внутри try
- Проверка ответаHTTP-ошибку распознаём через response.ok
- catch / finallyПоказываем ошибку и возвращаем кнопку в рабочее состояние
Вокруг вызова стоит try/catch, но ошибка async-функции всё равно уходит мимо него. Обычно дело в том, что код не дождался Promise. Разберём обработчик кнопки, который ждёт ответ, проверяет HTTP-статус и данные, а затем возвращает интерфейс в рабочее состояние независимо от результата.
Один обработчик со всеми исходами
const button = document.querySelector('#refresh');
const status = document.querySelector('#status');
async function readCounter() {
const response = await fetch('/api/counter');
if (!response.ok) throw new Error('HTTP ' + response.status);
const value = await response.json();
if (!Number.isInteger(value.count) || value.count < 0) {
throw new Error('Неверный счётчик');
}
return value.count;
}
button.addEventListener('click', async function () {
button.disabled = true;
try {
status.textContent = String(await readCounter());
} catch (error) {
status.textContent = 'Не удалось обновить счётчик';
} finally {
button.disabled = false;
}
});Пример объединяет несколько возможных отказов: сетевую ошибку, неуспешный HTTP-статус, повреждённый JSON и неверное значение поля. Fetch сам по себе не отклоняет Promise только из-за ответа 404, поэтому статус проверяется явно. Блок finally восстанавливает кнопку после успеха и ошибки. Текст для пользователя отделён от технических деталей; если требуется журналирование, сведения об ошибке передают в предусмотренный проектом канал без содержимого приватного ответа.
Не теряем незавершённую работу
Если убрать await перед readCounter, управление может выйти из try раньше, чем возникнет отказ. Аналогичная проблема появляется у асинхронного callback внутри forEach: внешний цикл не ожидает возвращаемые Promise. Для последовательной обработки удобен цикл с await внутри; для параллельной нужно явно собрать операции и определить политику ошибок. Выбор влияет на порядок выполнения и нагрузку, поэтому его нельзя считать чисто синтаксической заменой.
Отключение кнопки предотвращает повторное нажатие только в этом интерфейсе. Оно не гарантирует единственность серверной операции и не управляет запросами из других вкладок. В примере выполняется чтение; для изменения данных понадобятся дополнительные договорённости. Убедитесь также, что элементы существуют к моменту подключения обработчика. Функция, которая сама перехватила ошибку и вернула обычное значение, считается успешно завершившейся: вызывающая сторона больше не увидит отказ автоматически.
Сеть, HTTP-ошибка и неверные данные
Проверьте нормальное число, отрицательное значение, HTML вместо JSON, ответ 500 и отключённую сеть. При отказе сообщение должно появиться, а кнопка — снова включиться. Посмотрите консоль на необработанные Promise. Отдельно проверьте ноль: проверка на «пустое» не должна отклонять допустимое значение.
