在 javascript 中,returns 承诺并重试内部异步进程最佳实践的函数

In javascript, a function which returns promise and retries the inner async process best practice

我有一个函数,其中 returns 一个 javascript Promise 并且在其中运行一些异步代码。异步代码需要重试几次以防失败。 我一直在这样做,直到我观察到一些奇怪的行为,这让我怀疑我是否做对了。所以我不得不改变它。两种截断的方法都在这里。 我知道为什么第一种方法 (asyncFunc) 不起作用,如果有人可以分享一些关于它的技术清晰度,我将不胜感激。 对于第二种方法 (ayncFunc_newer) 有什么建议可以做得更好吗?

var _retryCount = 0;

// this is what I was doing
function asyncFunc () {
 return new Promise(function(fulfill, reject) {
  doAsync()
   .then(fulfill)
   .catch(retry);

  function retry(promiseResult) {
   if(_retryCount < 3) {
    _retryCount++;
    return asyncFunc();
   }
   else {
    reject(promiseResult);
   }
  }
 });
}

// this what I'm doing now
function ayncFunc_newer() {
    return new Promise(function(fulfill, reject) {
        var retryCount = 0;

        doAsync()
            .then(fulfill)
            .catch(onReject);

        function onReject(bmAuthError) {
            if(retryCount < 3) {
                retryCount++;
                logWarning(error);
                
                doAsync()
                 .then(fulfill)
                 .catch(onReject);
            }
            else {
                fulfill(false);
            }
        }
    });                 
};

最佳做法是避免 promise constructor anti-pattern。基本上,new Promise 主要用于包装非承诺 API,因此如果您的函数已经 return 承诺,那么通常有一种方法可以避免使用它。

如果您的重试次数很少,那么您的情况很简单:

function ayncFunc() {
  return doAsync().catch(doAsync).catch(doAsync).catch(doAsync);
};

对于可配置的重试次数,您可以将其扩展为:

var retries = 3;

function ayncFunc() {
  var p = doAsync();
  for (var i = 0; i < retries; i++) {
    p = p.catch(doAsync);
  }
  return p;
};

或者对于更多的重试次数,您可以使用递归方法:

function ayncFunc() {
  function recurse(i) {
    return doAsync().catch(function(e) {
      if (i < retries) {
        return recurse(++i);
      }
      throw e;
    });
  }
  return recurse(0);
};

var console = { log: msg => div.innerHTML += msg + "<br>" };

function doAsync() {
  console.log("doAsync");
  return Promise.reject("Nope");
}

function ayncFunc() {
  return doAsync().catch(doAsync).catch(doAsync).catch(doAsync);
};

var retries = 3;

function ayncFunc2() {
  var p = doAsync();

  for (var i=0; i < retries; i++) {
    p = p.catch(doAsync);
  }
  return p;
};

function ayncFunc3() {
  function recurse(i) {
    return doAsync().catch(function(e) {
      if (i < retries) {
        return recurse(++i);
      }
      throw e;
    });
  }
  return recurse(0);
};

ayncFunc().catch(function(e) { console.log(e); })
.then(ayncFunc2).catch(function(e) { console.log(e); })
.then(ayncFunc3).catch(function(e) { console.log(e); });
<div id="div"></div>