Асинхронные запросы: состояния загрузки, ошибки и повторная попытка

Интерфейс списка с отдельными состояниями загрузки и ошибки на экране

Сетевой запрос — это несколько возможных состояний, а не только await fetch. Страница должна отличать ожидание, пустой ответ, ошибку и готовые данные. Сделаем локальный список с повторной попыткой: кнопка блокируется на время запроса, а исключение не оставляет интерфейс в вечной загрузке.

Два файла для загрузки списка с повтором

index.html

<!doctype html>
<html lang="ru"><meta charset="utf-8"><title>Загрузка списка</title>
<button id="load" type="button">Загрузить или повторить</button>
<p id="state" aria-live="polite">Данные ещё не загружены</p><ul id="items"></ul>
<script>
const button = document.querySelector('#load');
const state = document.querySelector('#state');
const list = document.querySelector('#items');
async function loadItems(fetcher = fetch) {
  const response = await fetcher('./items.json');
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  const data = await response.json();
  if (!Array.isArray(data) || !data.every(x => typeof x === 'string')) {
    throw new TypeError('Ожидается массив строк');
  }
  return data;
}
button.addEventListener('click', async () => {
  button.disabled = true;
  state.textContent = 'Загрузка…';
  list.replaceChildren();
  try {
    const data = await loadItems();
    list.replaceChildren(...data.map(text => {
      const li = document.createElement('li'); li.textContent = text; return li;
    }));
    state.textContent = data.length ? `Получено: ${data.length}` : 'Список пуст';
  } catch { state.textContent = 'Не удалось загрузить список. Можно повторить.'; }
  finally { button.disabled = false; }
});
</script></html>

items.json

["Разминка", "Основная часть", "Заминка"]

Сохраните оба файла рядом и запустите python -m http.server 8000 из этой папки. Откройте http://localhost:8000. Для проверки 404 временно переименуйте только учебный items.json, затем верните и повторите запрос. Не выполняйте такой тест на рабочем источнике данных.

Состояния и наблюдаемый результат
Что сравнить На что смотреть Что сделать
Ожидание Кнопка недоступна Нет повторных параллельных запросов
HTTP-ошибка Ответ получен, но ok равен false Показать понятную ошибку
Неверный формат JSON не соответствует контракту Не строить интерфейс из случайного объекта
Пустой массив Корректный ответ без элементов Показать отдельное пустое состояние

Почему try недостаточно без проверки ok

MDN поясняет, что HTTP-ответ 404 сам по себе не отклоняет promise fetch. Поэтому статус проверяется явно. Затем отдельно может завершиться ошибкой чтение JSON. Проверка структуры нужна уже после синтаксического разбора: корректный JSON ещё не означает массив строк.

  • Проверить успешную загрузку и пустой массив.
  • Проверить HTTP-ошибку.
  • Проверить повреждённый JSON и объект вместо массива.
  • Убедиться, что после ошибки кнопка снова доступна.

Вопросы и ответы

Нужен ли no-cors при ошибке?

Нет. Он не является универсальным исправлением и может сделать ответ недоступным для чтения. Разбирайте причину и серверные условия.

Почему очищается прежний список?

Это выбранное поведение примера. В другом продукте можно сохранять старые данные с явной отметкой об их состоянии.

Где журналировать техническую причину?

В подходящей системе диагностики без лишних персональных данных. Пользовательское сообщение и технический лог имеют разные задачи.

Повтор безопасен для любого запроса?

Нет. Здесь только чтение локального файла. Для операций изменения данных нужна отдельная защита от повторов.

Источники: developer.mozilla.org.

Похожие записи