> Как реализовать функцию retry для повторного вызова асинхронной функции при ошибке в JavaScript (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Яндекс
Стек: JavaScript
> Пример ответа
Короткий ответ
Функция retry для асинхронной функции реализуется через рекурсивный вызов или цикл с try/catch, повторяя вызов при ошибке до достижения лимита попыток. Ключевые моменты: передача оригинальных аргументов, настройка задержки между попытками (exponential backoff), обработка ошибок после исчерпания попыток. Важно корректно обрабатывать reject и не терять контекст вызова.
Подробное объяснение
Основная задача retry - повысить отказоустойчивость при работе с ненадёжными асинхронными операциями (сетевые запросы, API). Реализация строится на обёртке, которая перехватывает reject промиса и повторяет вызов.
Базовый паттерн:
- Принимает асинхронную функцию, количество попыток, опционально задержку и условие для повторной попытки.
- Использует рекурсию или цикл for/while.
- При ошибке проверяет, остались ли попытки, и либо ждёт (через setTimeout или sleep), либо пробрасывает ошибку.
Варианты усложнения:
- Exponential backoff: увеличение задержки между попытками (например, 1с, 2с, 4с).
- Jitter: случайное отклонение задержки для избежания thundering herd.
- Retry condition: повторять только для определённых типов ошибок (например, 5xx, но не 4xx).
- Max retry timeout: общий лимит времени на все попытки.
На практике
В реальных проектах retry часто используется с fetch, WebSocket, или любыми внешними вызовами. Полезно добавить логирование каждой попытки и финальной ошибки. Для Node.js можно использовать готовые библиотеки (p-retry, async-retry), но понимание реализации важно для кастомизации.
Типичный сценарий: retry для POST-запроса к API, где временные сбои сервера - норма. Важно не повторять идемпотентные операции без проверки.
Пример кода
JAVASCRIPTasync function retry(asyncFn, { attempts = 3, delay = 1000, backoff = 2 } = {}) {for (let i = 0; i < attempts; i++) {try {return await asyncFn();} catch (error) {if (i === attempts - 1) throw error;await new Promise(resolve => setTimeout(resolve, delay * Math.pow(backoff, i)));}}}// Использованиеconst fetchWithRetry = () => retry(() => fetch('https://api.example.com/data'),{ attempts: 5, delay: 500 });
Более гибкая версия с поддержкой retry condition:
JAVASCRIPTasync function retryWithCondition(asyncFn, options = {}) {const { attempts = 3, delay = 1000, shouldRetry = () => true } = options;for (let i = 0; i < attempts; i++) {try {return await asyncFn();} catch (error) {if (i === attempts - 1 || !shouldRetry(error)) throw error;await new Promise(resolve => setTimeout(resolve, delay));}}}
Как отвечать на собеседовании
Начни с простого определения и базовой реализации. Затем покажи, как добавляешь задержку и exponential backoff. Упомяни edge cases: потеря контекста (this), передача аргументов, обработка синхронных ошибок. Покажи понимание trade-off между retry и circuit breaker. Если спросят про параллельные вызовы - обсуди проблемы с очередностью и idempotency.
Что проверяет интервьюер
- Понимание асинхронности и промисов.
- Умение работать с рекурсией/циклами в асинхронном контексте.
- Знание паттернов отказоустойчивости (retry, backoff, jitter).
- Внимание к деталям: потеря контекста, проброс ошибок, бесконечные циклы.
- Способность проектировать гибкие API (опции, колбэки).
Типичные ошибки
- Бесконечный цикл при неправильном счётчике попыток.
- Потеря контекста (this) при передаче метода объекта.
- Игнорирование задержки - мгновенный повтор при ошибке.
- Неправильная обработка последней ошибки (проброс не той ошибки).
- Отсутствие проверки типа ошибки - повтор даже для 4xx.
- Использование рекурсии без учёта стека вызовов (хотя для async/await это не проблема).
> Похожие задачи по frontend
Реализовать функцию, принимающую массив промисов и возвращающую массив результатов или первый reject в JavaScript
Как реализовать мемоизацию функции в JavaScript
Как обрабатывать дублирующиеся ключи при преобразовании массива объектов в объект в JavaScript
Как отфильтровать строку, чтобы оставить только буквы с помощью регулярных выражений в JavaScript
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью