JavaScript AbortController: отменить fetch-запрос
Отменить запрос fetch можно через AbortController: передайте controller.signal в опции, затем вызовите controller.abort(). Promise завершится ошибкой AbortError; отличайте её от сетевых сбоев и HTTP-ошибок.
Создать отменяемый запрос
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
}В приложении обычно отменяют предыдущий запрос при смене фильтра, уходе со страницы или размонтировании компонента.
Обработать отмену отдельно
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 отдельно.
Событие | Результат |
|---|---|
|
|
HTTP 500 | Promise обычно разрешается объектом |
Нет сети | Promise отклоняется сетевой ошибкой |
Можно ли использовать один controller для нескольких запросов?
Да, один signal отменит все операции, которым он передан. Создайте новый controller для следующей независимой группы запросов.
Как задать таймаут?
В современных средах можно использовать AbortSignal.timeout(ms); для широкой совместимости создайте таймер, который вызывает controller.abort() и очистите его после завершения.