CODEGURU

JS: Повторяем запрос, пока не получим ответ

Бывают ситуации, когда нам необходимо несколько раз повторить запрос к API. Например, мы что-то отправили на сервер и в следующем запросе нам нужно получить от него новую информацию. Но на сервере процесс может немного затянуться и нам нужно повторять запрос несколько раз, пока не получим нужный ответ.

Прям пример из реальной жизни. В текущем проекте у меня была задача получить от сервера ответ. Если ответ ещё не готов, то сервер возвращает ошибку. Получив эту ошибку, я должен через секунду снова повторить запрос. И так в течение минуты. Если ответа так и нет, то показать пользователю сообщение об ошибке. Вот такую функцию и напишем.

Определимся с логикой. Наша функция принимает на вход url запроса и количество попыток (мы же не хотим вечно отправлять запросы). Далее мы отправляем запрос. Если всё ок, то возвращаем результат запроса. Если получаем ошибку, то прям внутри функции вызываем её саму (о, рекурсия), но количество попыток уменьшаем на один. Кстати, раз мы уменьшаем количество попыток, то перед вызовом функции нужно проверить сколько их там осталось. И если там 1 или меньше, то закончить выполнение, вернув ошибку.

const request_retry = async({ url, options, n }) => {
 try {
   return await fetch(url, options);
 } catch (e) {
   if (n <= 1) throw e;
   return await request_retry({url, options, n: n - 1});
 }
}

Вот так, но мы забыли про то, что запрос нужно отправлять раз в секунду. Нужно как-то выставить задержку. Для этого напишем вспомогательный метод.

const sleep = (ms) => {
 return new Promise(resolve => setTimeout(resolve, ms));
}

Здесь мы просто возвращаем промис, который резолвится через указанный промежуток времени. И допишем нашу основную функцию.

const request_retry = async({ url, options, n }) => {
 try {
   return await fetch(url, options);
 } catch (e) {
   if (n <= 1) throw e;
   await sleep(1000);
   return await request_retry({url, options, n: n - 1});
 }
}

Ну вот, теперь, чтобы посылать повторные запросы в течение максимум минуты мне достаточно вызвать эту функцию request_retry(url, options, 60). 🤘