Retry on Javascript.Promise.reject a limited number of times or until success

两盒软妹~` 提交于 2019-12-06 04:24:27

问题


I have a function say myMainFunction that is called from a client, that in turn calls mypromisified function.

Scenario: mypromisified function can fail intermittently and I need to call this function with a delay (at an exponential increase) until success or until max no of tries reached.

What I have so far

The following code illustrates my scenario and repeats itself until success, but it tries indefinitely and not until certain count is reached

// called once from the client
myMainFuntion();

function rejectDelay(delay, reason) {
   // call main function at a delayed interval until success 
   // but would want to call this only a limited no of times
    setTimeout(() => {
      myMainFuntion(); // calling main function again here but with a delay
    }, delay);
}


function myMainFuntion() {
  var delay = 100;
  var tries = 3;
  tryAsync().catch(rejectDelay.bind(null, delay));
}

function tryAsync() {
  return new Promise(function(resolve, reject) {
    var rand = Math.random();
    console.log(rand);
    if (rand < 0.8) {
      reject(rand);
    } else {
      resolve();
    }
  });

}

while loop inside the rejectDelay would certainly not work as the counter would increment even before the actual function inside setInterval is executed, so am unsure as to how to go about this? so...

I tried promisifying the setInterval something like this knowing it will fail :( as it doesnt decrement the counter, but not sure how to get it right either .

function rejectDelay(delay, maximumTries, reason) {
  return new Promise(function (resolve, reject) {
    console.log(tries + ' remaining');
    if (--maximumTries > 0) {
      setTimeout(function() {
        foo();
      }, 500);
    } 
  });
}
function myMainFunction() {
  var delay = 100;
  var maximumTries = 3;
  tryAsync().catch(rejectDelay.bind(null, delay, maximumTries));
}

回答1:


Using a couple of helper functions I've used a lot, this becomes very easy

The "helpers"

Promise.wait = (time) => new Promise(resolve => setTimeout(resolve, time || 0));
Promise.retry = (cont, fn, delay) => fn().catch(err => cont > 0 ? Promise.wait(delay).then(() => Promise.retry(cont - 1, fn, delay)) : Promise.reject('failed'));

The code:

function myMainFuntion() {
      var delay = 100;
      var tries = 3;
      Promise.retry(tries, tryAsync, delay);
}

ES5 versions of the helpers

Promise.wait = function (time) {
    return new Promise(function (resolve) {
        return setTimeout(resolve, time || 0);
    });
};
Promise.retry = function (cont, fn, delay) {
    return fn().catch(function (err) {
        return cont > 0 ? Promise.wait(delay).then(function () {
            return Promise.retry(cont - 1, fn, delay);
        }) : Promise.reject('failed');
    });
};



回答2:


A slightly different approach that uses "asynchronous recursion" to call a nested function within a function that returns a promise:

function retry( func, maxTries, delay) {
    var reTry = 0;
    return new Promise( function(resolve, reject) {
        function callFunc() {
          try
          {
              func().then(resolve, function( reason) {
                  if( ++reTry >= maxTries) {
                      reject( reason);
                  }
                  else {
                      setTimeout( callFunc,
                         typeof delay=="function" ? delay( retry) : delay );
                  }
              });
          }
          catch(e) {
              reject(e);
          }
        }
        callFunc();      
    });
}

//  ******* run snippet to test ********


var retryCount = 0;
function getDelay( n) {
//    return 100 * n*n + 500; // for example
      ++ retryCount;
      return 100;  // for testing

}

function testFunc() {
    return Math.random() < 0.8 ? Promise.reject("too many tries") : Promise.resolve( "success");
}

retry( testFunc, 5, getDelay).then(
 function(data) { console.log("data: %s, retryCount %s", data, retryCount);},
 function(reason){console.log("reason: %s, retryCount %s", reason, retryCount);}
)


来源:https://stackoverflow.com/questions/42429590/retry-on-javascript-promise-reject-a-limited-number-of-times-or-until-success

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!