JavaScript AbortController: отменить fetch-запрос

Категория: JavaScript · Язык: JavaScript · Обновлено:

Отменить запрос fetch можно через AbortController: передайте controller.signal в опции, затем вызовите controller.abort(). Promise завершится ошибкой AbortError; отличайте её от сетевых сбоев и HTTP-ошибок.

Создать отменяемый запрос

JavaScript
const controller = new AbortController();
globalThis.fetch = (_url, {signal}) => new Promise((_resolve, reject) => {
  signal.addEventListener('abort', () => reject(new DOMException('Aborted', 'AbortError')), {once: true});
});
const request = fetch('https://example.com/api/items', {signal: controller.signal});
controller.abort();

try {
  await request;
} catch (error) {
  console.log(error.name); // AbortError
}

В приложении обычно отменяют предыдущий запрос при смене фильтра, уходе со страницы или размонтировании компонента.

Обработать отмену отдельно

JavaScript
const controller = new AbortController();
try {
  const response = await fetch('/api/items', {signal: controller.signal});
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
} catch (error) {
  if (error.name === 'AbortError') console.log('Запрос отменён');
  else console.error('Сетевая ошибка:', error);
}

Отклонение fetch из-за HTTP 404 или 500 не является отменой: проверяйте response.ok отдельно.

Событие

Результат

controller.abort()

fetch отклоняется с AbortError

HTTP 500

Promise обычно разрешается объектом Response

Нет сети

Promise отклоняется сетевой ошибкой

Можно ли использовать один controller для нескольких запросов?

Да, один signal отменит все операции, которым он передан. Создайте новый controller для следующей независимой группы запросов.

Как задать таймаут?

В современных средах можно использовать AbortSignal.timeout(ms); для широкой совместимости создайте таймер, который вызывает controller.abort() и очистите его после завершения.