Как AbortController помогает отменять ненужные запросы для решения проблемы race condition
Что проверяют
Понимаете ли вы, откуда в интерфейсе берётся гонка запросов и почему отмена решает её лишь частично. Следом обычно просят написать поиск с автодополнением или эффект в React с отменой.
Как отвечать
Гонка возникает так: пользователь набирает «re», потом «react», ответ на первый запрос приходит позже второго и перезаписывает свежие результаты старыми. AbortController позволяет оборвать устаревший запрос:
- контроллер и сигнал:
const controller = new AbortController(), вfetch(url, { signal: controller.signal })передаётся сигнал, вызовcontroller.abort()отменяет запрос; - что происходит при отмене: промис
fetchотклоняется сDOMExceptionс именемAbortError. Если отмена случилась во время чтения тела, отклонится иresponse.json(); - один контроллер на один запрос: отменённый сигнал остаётся отменённым навсегда, поэтому на каждый новый запрос создаётся новый контроллер, а предыдущий хранится в переменной или
useRef; - в React: контроллер создаётся внутри
useEffect, а в функции очистки вызываетсяabort(). При смене зависимости эффект сам отменит прошлый запрос; - полезные дополнения:
AbortSignal.timeout(5000)даёт таймаут без ручного таймера,AbortSignal.any()объединяет несколько сигналов. axios и TanStack Query принимают тот жеsignal.
Где спотыкаются
Думают, что abort() останавливает работу сервера. Браузер лишь перестаёт ждать ответ, а POST на сервере вполне может выполниться. Для запросов с побочным эффектом отмена не заменяет идемпотентность.
Не отделяют AbortError от настоящих ошибок и показывают пользователю «Не удалось загрузить» на каждое нажатие клавиши. В catch отмену нужно тихо пропускать.
Считают, что отмена закрывает гонку целиком. Если данные уже разобраны и дошли до обработчика, abort() их не остановит, поэтому перед записью в состояние стоит проверить signal.aborted или сравнить идентификатор запроса. И ещё: в StrictMode эффект в режиме разработки срабатывает дважды, так что первый отменённый запрос во вкладке Network не баг.