Как рекурсивно проверять условие повторных запросов с учётом счётчика попыток в JavaScript
Что проверяют
Умеете ли вы написать повтор, который не превращается в DDoS собственного API: с лимитом попыток, паузой и разумным выбором, какие ошибки вообще стоит повторять. Следом часто просят добавить таймаут и отмену или спрашивают, чем рекурсия здесь лучше цикла.
Как отвечать
Каркас: fetchWithRetry(url, options, attempt = 0), где attempt это номер текущей попытки, а лимит maxAttempts приходит в настройках.
- условие повтора: повторяют сетевые ошибки (
fetchотклоняет промис сTypeError), таймаут,429и5xx. На HTTP-ошибкахfetchпромис не отклоняет, поэтомуresponse.okпроверяется вручную.400,401,404повторять бессмысленно, аPOSTбез ключа идемпотентности опасно; - пауза: экспоненциальная задержка с джиттером, например
base * 2 ** attemptплюс случайная добавка, черезawait new Promise(r => setTimeout(r, delay)). Для429сначала смотрят заголовокRetry-After; - рекурсия:
return fetchWithRetry(url, options, attempt + 1)в ветке ошибки. Безreturnрезультат повторной попытки потеряется, и вызывающий получитundefined; - таймаут и отмена:
AbortSignal.timeout(5000)на каждую попытку и внешний сигнал от компонента, объединённые черезAbortSignal.any(). Если пользователь ушёл со страницы,AbortErrorне повторяют; - исчерпание попыток: пробрасывают последнюю настоящую ошибку, например через
new Error("...", { cause: err }), а не безликое «всё упало».
Про рекурсию скажите честно: глубина равна числу попыток, и стек не копится, потому что каждый вызов идёт после await в новой микрозадаче. Цикл for с await читается не хуже, и на ревью его часто предпочитают. В React-проектах повторы уже умеет TanStack Query (retry, retryDelay).
Где спотыкаются
Повторяют всё подряд, включая 400 и 401. Пользователь ждёт лишние попытки, а неверный токен от этого верным не станет.
Повторяют без задержки. Запросы подряд во время сбоя только добавляют серверу нагрузки, а у тысяч клиентов без джиттера повторы приходят одной волной.
Путают счётчик: при retries = 3 и проверке retries > 0 запросов на деле будет четыре. Проговорите, что считаете: попытки или повторы.