为什么我的通用Promise重试函数的行为不像我的特定函数那样?

时间:2019-03-05 05:13:14

标签: javascript node.js promise

我有一种非通用的方法,可以通过指数回退重试到Internet的呼叫。我正在尝试以一种通用的方式来实现它,到目前为止,我的工作方式只有一半有效。

全部要旨

如下所示的两种实现方法与我几乎相同,甚至每次 request.get 成功时都可以使用。

但是,当 request.get 随机抛出错误时,重试逻辑的工作方式将有所不同。使用第一种非泛型方法,一切都会按预期工作,重试呼叫直到成功或重试 ==0。使用第二种非泛型方法,重试逻辑反复触发直到 retries < / em> ==0。它不会第二次,第三次,第四次等向互联网发出呼叫。有什么作用?

我了解所有这些信息,因为我在自己的控制下进行了模拟 request.get()方法的测试,并以正确的响应或错误返回。

工作方法

好的,所以我有这样的工作递归重试逻辑,如下所示:

function getPageOfThreadsWithRetry(access_token, nextPageToken, retries, delay) {
  return new Promise((resolve, reject) => {
    getPageOfThreads(access_token, nextPageToken).then((results) => {
        resolve(results);
    }).catch((err) => {
      if (retries == 0) {
        reject(err);
      } else {
        let retry = function() {
          retries--;
          delay = delay * DELAY_MULTIPLIER;
          resolve(getPageOfThreadsWithRetry(access_token, nextPageToken, retries, delay));
      }
      setTimeout(retry, delay);
    }
  });
});

getPageOfThreads(access_token,nextPageToken)是一个简单的函数,它返回一个包装了 request.get()调用的promise,并在成功的情况下进行解析,并在失败时拒绝错误的情况。

function getPageOfThreads(access_token, pageToken) {
  return new Promise((resolve, reject) => {
    let options = createOptions(access_token, pageToken);
    request.get(options, (error, response, body) => {
      if (!error && response.statusCode == 200) {
        body = JSON.parse(body);
        resolve(body)
      } else {
        reject(error);
      }
    });
  });
}
工作递归异步函数内部调用

getPageOfThreadsWithRetry(...),该函数将一直调用直到没有 nextPageToken 为止。呼叫看起来像:

let delay = INIT_RETRY_DELAY;
let retries = MAX_RETRIES;
let response = await getPageOfThreadsWithRetry(access_token, nextPageToken, retries, delay).catch((error) => {

});

这按预期工作,调用 getPageOfThreads()并一次又一次地返回 response 对象,直到没有nextPageToken。  如果错误被随机抛出在某个地方,它会以指数回退的方式重试该呼叫,直到它成功或尝试了超过 try 次。

半工作方法

我想在我的应用程序的许多地方实现这种功能。因此,我试图提出一个通用的实用程序函数来完成此任务。到目前为止,我已经提出了这一点(在这种情况下,prms == promise):

function retryPromise(prms, retries, delay, delayMultiplier) {
  return new Promise((resolve, reject) => {
    prms.then((results) => {
      resolve(results);
    }).catch((err) => {
      if (retries == 0) {
        reject(err);
      } else {
        let retryFunc = function() {
          retries--;
          delay = delay * delayMultiplier;
          resolve(retryPromise(prms, retries, delay, delayMultiplier));
        }
        setTimeout(retryFunc, delay);
      }
    });
  });
}

尝试这样称呼它:

function getPageOfThreadsWithRetry(access_token, nextPageToken) {
  let delay = INIT_RETRY_DELAY;
  let retries = MAX_RETRIES;
  let delayMultiplier = DELAY_MULTIPLIER;
  let prms = getPageOfThreads(access_token, nextPageToken);
  return retryPromise(prms, retries, delay, delayMultiplier);
}

并以与以前类似的方式从上方调用 getPageOfThreadsWithRetry()

let response = await getPageOfThreadsWithRetry(access_token, nextPageToken).catch((err) => {
});

第二种方法对我来说比较理想,因为它可以在我接到互联网的任何地方实施,并提取所有代码的详细信息,这些代码取决于互联网的响应。

我知道这是一个相当复杂的问题,所以我真的很感谢愿意提供一些思想和时间的人,尤其是那些可能有答案的人?

即使您的答案涉及一种完全不同的方法,我也想学习您可能知道的东西。

-谢谢您的时间

1 个答案:

答案 0 :(得分:0)

在第一个方法中,在递归函数request.get中调用getPageOfThreadsWithRetry。但是在第二种方法中,request.get在递归函数retryPromise之外被调用。

我建议您将retryPromise签名更改为类似

function retryPromise(promiseCreator, retries, delay, delayMultiplier) {
  return new Promise((resolve, reject) => {
    promiseCreator()
      .then(resolve)
      .catch((err) => {
        if (retries == 0) {
          reject(err);
        } else {
          let retryFunc = function() {
            retries--;
            delay = delay * delayMultiplier;
            resolve(retryPromise(promiseCreator, retries, delay, delayMultiplier));
          }
          setTimeout(retryFunc, delay);
        }
      });
  });
}

并像使用它

function getPageOfThreadsWithRetry(access_token, nextPageToken) {
  let promiseCreator = () => getPageOfThreads(access_token, nextPageToken);
  return retryPromise(promiseCreator, retries, delay, delayMultiplier);
}