AngularJS Accelerated Promises

I am having trouble getting the repeat function to work and was hoping for some help. I have a $ resource that I want to call until a success condition occurs or the maximum retries are exceeded.

The problem I seem to be running into is that in my retry function I call another promise and the condition will be checked there. I could get the code to function as expected by removing the added promise and creating a default success condition after a few tries, but I can't figure out how to properly add a new call to the function.

resource

is the fallback for the Angular $ resource that $ prom returns

My code looks like this:

resource.$promise.then(function (response) {
  return keepTrying(state, 5);
 }).then(function (response) {

 }).catch(function (err) {
   console.log(err);
 });

      

And the keepTrying function:

function keepTrying(state, maxRetries, deferred) {
  deferred = deferred || $q.defer();
  resource.$promise.then(function (response) {
    success = response;
  });
  if (success) {
    return deferred.resolve(success);
  } else if (maxRetries > 0) {
    setTimeout(function () {
      keepTrying(state, maxRetries - 1, deferred);
     }, 1000);
   } else if (maxRetries === 0) {
     deferred.reject('Maximum retries exceeded');
   }
   return deferred.promise;
 }

      

+3


source to share


2 answers


The problem with your attempt is that you are not re-requesting the resource, but using the promise for the already requested resource over and over again.

What you need to do is use a function that (a) initiates a request and (b) returns a promise for that initiated request. Something like that:

function () { return $resource.get().$promise; }

      

Then you can pipe it to something like that, which will do the repetitions.

function retryAction(action, numTries) {
    return $q.when().then(action)
    .catch(function (error) {
        if (numTries <= 0) {
            throw error;
        }
        return retryAction(action, numTries - 1);
    });
}

      



Here's how you do it:

retryAction(function () { return $resource.get().$promise; }, 5)
.then(function (result) {
    // do something with result 
});

      

One of the nice things about this approach is that even if the function you pass to it throws an error when called, or doesn't return a promise at all, the repeat function and return the result via resolved promises will work.

Example

+8


source


You can implement a retryOperation function that returns a new promise on error up to the maximum number of retries passed as an argument:

function retryOperation(retryCount) {
    var count = 0;
    function success(result) {
        return result;
    }
    function error(result) {
         ++count;
         if (count <= retryCount)
             return $resource(...).query().$promise.then(success, error);

         throw 'max retries reached';
    }
    return $resource(...).query().$promise.then(success, error);
}

      

Using



retryOperation(3).then(
    function success(result) {
        // done!
    }, 
    function error(reason) {
         alert(reason);
    });

      

var app = angular.module('app', []);
app.controller('ctrl', function($q) {
  function retryOperation(count) {
    var retryCount = 0;

    function operation() {
      var deferred = $q.defer();
      deferred.reject('failed');
      return deferred.promise;
    }

    function success(result) {
      return result;
    }

    function error(result) {
      ++retryCount;
      if (retryCount <= count) {
        alert('retrying ' + retryCount);
        return operation().then(success, error);
      }
      throw 'maximum retries reached';
    }
    return operation().then(success, error);
  }

  retryOperation(3).then(
    function success(result) {
      alert('done');
    },
    function error(result) {
      alert(result);
    });


});
      

<html>

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

</head>

<body ng-app="app" ng-controller="ctrl">
  <input type="text" ng-model="name" />{{name}}
</body>

</html>
      

Run codeHide result


+1


source







All Articles