Как реализовать тайм-аут для асинхронного запроса, если ответ приходит дольше одной секунды в JavaScript?
Что проверяют
Знаете ли вы, что тайм-аут без отмены запроса только прячет проблему, и умеете ли пользоваться AbortController. Следом обычно просят совместить тайм-аут с отменой при уходе со страницы или при новом вводе в поиске.
Как отвечать
Современный ответ укладывается в одну строку: fetch(url, { signal: AbortSignal.timeout(1000) }). Через секунду запрос действительно прерывается, а промис отклоняется с DOMException с именем TimeoutError.
Дальше покажите, что понимаете механику:
- ручной вариант:
const controller = new AbortController(),setTimeout(() => controller.abort(), 1000), передатьcontroller.signalвfetchи обязательно вызватьclearTimeoutвfinally, иначе таймер висит после успешного ответа; - несколько причин отмены:
AbortSignal.any([userSignal, AbortSignal.timeout(1000)])отменит запрос и по тайм-ауту, и по действию пользователя; - разбор ошибок:
TimeoutErrorозначает тайм-аут,AbortErrorручную отмену,TypeErrorсетевой сбой. Ответ 404 или 500 промис не отклоняет вовсе,response.okпроверяется отдельно; - тело ответа: промис
fetchвыполняется, когда пришли заголовки, аresponse.json()может читать тело ещё долго. Сигнал прерывает и чтение тела, а обёртка только вокругfetchего не покрывает.
Promise.race с таймером тоже рабочий ответ, но честно назовите минус: запрос продолжает идти, занимает соединение и тратит трафик, просто результат выбрасывается. В React отмену ставят в функцию очистки useEffect, чтобы старый ответ не перетёр новый.
Уточните у интервьюера сценарий. Секунда для мобильной сети жёсткий порог, и иногда задача на самом деле другая: через секунду показать скелетон, но ответ всё же дождаться.
Где спотыкаются
Делают Promise.race и считают запрос отменённым. Во вкладке Network он спокойно досчитывается, а при поиске по мере ввода старые ответы приходят позже новых.
Переиспользуют один AbortController на несколько запросов. Сигнал, отменённый однажды, остаётся отменённым, и все следующие запросы падают сразу.
Ловят все ошибки одним catch и показывают «Сервер не отвечает» на отмену, которую инициировал сам пользователь.