Обработчик ошибок рефакторинга для рекурсивной повторной попытки неудачных вызовов api

#javascript #api #recursion #closures

Вопрос:

Мне нужна помощь в организации моего кода, чтобы я мог рекурсивно повторить неудачные запросы api. Вот пример функции, которая вызывает api (у меня есть несколько подобных функций, которые выполняют различные вызовы api с полезной нагрузкой и принимают функцию обратного вызова, в рамках обещания функция ApiCall издевается над ней):

 function boilerPlateApiCall() {
  return new Promise(((resolve, reject) => {
    // make an api call
    apiCall('GET',(err, res) => {
      if (err) { return reject(err); }
      resolve(res);
    });
  }))
    .then(res => res.data)
    .catch(handleErrors(boilerPlateApiCall, []));
}
 

Вот моя handleErrors функция:

 function handleErrors(recursiveFunc, parameters) {    
    const handleError = function handleError(err) {        
        console.log('Error in request: ', recursiveFunc.name);
        console.log('Error is ', err);
        console.log('handleErrors');
      if (err.code === 401) {
        console.log('authorizing and trying again');        
      }
  
      if (err.code === 404) {
        console.log('404');
        return Promise.resolve();
      }
      if (err.code === 403 || err.code === 503) {
        console.log('too many requests');            
          setTimeout(() => {
            recursiveFunc(...parameters);
          }, 1000);
        }
        return Promise.reject(err);
      }
    };
    return handleError;
  }
 

handleErrors Функция используется в a .catch для всех методов api. Основная причина handleErrors заключается в регистрации ошибок и возможности получить имя функции, в которой возникает ошибка. Однако, исходя из структуры, в операторе if, который проверяет наличие кодов состояния 403 и 503, это будет выполняться бесконечно, если будут возвращены одни и те же коды.

Из-за структуры этого кода (в частности, функции catch в boilerPlateApiCall ) функция handleErrors вызывается всякий раз , когда возникает ошибка. Я не могу понять, как обернуть setTimeout рекурсивный вызов в какой-то тип закрытия, чтобы ограничить количество повторных попыток/попыток.

В идеале я хочу что-то подобное, но поскольку boilerPlateApiCall вызывает ошибки обработки в .catch, закрытие сбрасывается при каждой попытке:

 function handleErrors(recursiveFunc, parameters) {  
    let numberOfRetries = 5;
    const handleError = function handleError(err) {        
        console.log('Error in request: ', recursiveFunc.name);
        console.log('Error is ', err);
        console.log('handleErrors');
      if (err.code === 401) {
        console.log('authorizing and trying again');        
      }
  
      if (err.code === 404) {
        console.log('404');
        return Promise.resolve();
      }
      if (err.code === 403 || err.code === 503) {
        console.log('too many requests');
        if(numberOfRetries > 0){         
         numberOfRetries--   
          setTimeout(() => {
            recursiveFunc(...parameters);
          }, 1000);
        }
       }
        return Promise.reject(err);
      }
    };
    return handleError;
  }
 

Единственный способ, который я могу придумать для этого, — это, возможно, передавать каждой функции вызова api ( boilerPlateApiCall ) аргумент «повторная попытка», а затем передавать аргумент повторной попытки handleErrors .

Комментарии:

1. Если вы контролируете функции api, то , возможно boilerPlateApiCall (3 , ...moreArgs) , вызовете handleError (3, boilerplateApiCall, moreArgs) , который при сбое проверит, является ли numberOfRetries (этот первый параметр) положительным. Если это так, то он вызовет recursiveFunc (numberOfRetries - 1, ...moreArgs) , если это не так, вы переходите к окончательной ошибке. Все это зависит от того, сможете ли вы изменить API boilerPlateApiCall . Если ты не можешь этого сделать, тогда мне придется больше думать.

2. Спасибо, Скотт. У меня есть доступ к функциям api. Я думал об этом маршруте, но предпочел бы не идти этим путем, так как для получения дополнительного аргумента потребуется обновить множество функций. Я действительно в тупике, и, возможно, мне придется пойти по предложенному вами маршруту.