Skip to content Skip to sidebar Skip to footer

How To Retry An Xhr Request Which Returns A Promise Recursively For Atleast N Times On Status 0

I have written the below piece of code. makeRequest gets called and I want to retry this when xhr status is 0. The problem is I am not able to resolve the correct promise, the retr

Solution 1:

Here's how I'd approach it (see *** comments):

var makeRequest = function(method, urlToBeCalled, payload) {
    var deferred = $q.defer();
    var retries = 4;                     // *** Counterrun();                               // *** Call the workerreturn deferred.promise;

    // *** Move the actual work to its own functionfunctionrun() {
        var xhr = newXMLHttpRequest();
        xhr.open(method, encodeURI(urlToBeCalled), true);
        setHttpRequestHeaders(xhr);
        xhr.onload = function() {
            if (xhr.status === 200 && xhr.readyState === 4 && xhr.getResponseHeader('content-type') !== 'text/html') {
                try {
                    response = JSON.parse(xhr.response);
                    deferred.resolve(response);
                } catch (e) {
                    deferred.reject(e);
                }
            } elseif (xhr.status === 0) {
                // retryif (retries--) {          // *** Recurse if we still have retries run();
                } else {
                    // *** Out of retries
                    deferred.reject(e);
                }
            } else {
                // *** See note below, probably remove thistry {
                    response = JSON.parse(xhr.response);
                    deferred.reject(response);
                } catch (e) {
                    deferred.reject(xhr.response);
                }
            }
        };
        xhr.onerror = function() {
            deferred.reject(xhr.response);
        };
        xhr.send(payload);
    }
};

Side note: The content of your initial if body and the final else appear to be identical. I think I'd recast the entire onload:

xhr.onload = function() {
    if (xhr.readyState === 4) {
        // It's done, what happened?if (xhr.status === 200) {
            if (xhr.getResponseHeader('content-type') !== 'text/html') {
                try {
                    response = JSON.parse(xhr.response);
                    deferred.resolve(response);
                } catch (e) {
                    deferred.reject(e);
                }
            } else {
                // Something went wrong?
                deferred.reject(e);
            }
        } elseif (xhr.status === 0) {
            // retryif (retries--) {          // *** Recurse if we still have retries run();
            } else {
                // *** Out of retries
                deferred.reject(e);
            }
        }
    }
};

Re your comment:

This does resolve my current problem but is there a way to resolve all the promises which are added to call stack if any one of those is resolved?

Yes: To do that with Angular's $q (I assume that's what you're using), you can just pass the promise you get back from the recursive call into resolve on your deferred object: Since it's a promise, the deferred will wait for it to be settled and resolve or reject based on what that promise does. If you do this at every level in the chain, the resolutions work their way up the chain:

angular.module("mainModule", []).controller(
  "mainController",
  function($scope, $q, $http) {
    test(true).then(function() {
      test(false);
    });

    functiontest(flag) {
      log(flag ? "Testing resolved" : "Testing rejected");
      returnrecursive(3, flag)
        .then(function(arg) {
          log("Resolved with", arg);
        })
        .catch(function(arg) {
          log("Rejected with", arg);
        });
    }

    functionrecursive(count, flag) {
      log("recursive(" + count + ", " + flag + ") called");
      var d = $q.defer();
      setTimeout(function() {
        if (count <= 0) {
          // Done, settleif (flag) {
            log("Done, resolving with " + count);
            d.resolve(count);
          } else {
            log("Done, rejecting with " + count);
            d.reject(count);
          }
        } else {
          // Not done, resolve with promise from recursive calllog("Not done yet, recursing with " + (count - 1));
          d.resolve(recursive(count - 1, flag));
        }
      }, 0);
      return d.promise;
    }
  }
);

functionlog() {
  var p = document.createElement('pre');
  p.appendChild(
    document.createTextNode(
      Array.prototype.join.call(arguments, " ")
    )
  );
  document.body.appendChild(p);
}
pre {
  margin: 0;
  padding: 0;
}
<divng-app="mainModule"><divng-controller="mainController"></div></div><scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

You can do the same thing with JavaScript's own promises:

test(true).then(function() {
  test(false);
});

functiontest(flag) {
  log(flag ? "Testing resolved" : "Testing rejected");
  returnrecursive(3, flag)
    .then(function(arg) {
      log("Resolved with", arg);
    })
    .catch(function(arg) {
      log("Rejected with", arg);
    });
}

functionrecursive(count, flag) {
  log("recursive(" + count + ", " + flag + ") called");
  returnnewPromise(function(resolve, reject) {
    setTimeout(function() {
      if (count <= 0) {
        // Done, resolve with valueif (flag) {
          log("Done, resolving with " + count);
          resolve(count);
        } else {
          log("Done, rejecting with " + count);
          reject(count);
        }
      } else {
        // Not done, resolve with promise// from recursive calllog("Not done yet, recursing with " + (count - 1));
        resolve(recursive(count - 1, flag));
      }
    }, 0);
  });
}

functionlog() {
  var p = document.createElement('pre');
  p.appendChild(
    document.createTextNode(
      Array.prototype.join.call(arguments, " ")
    )
  );
  document.body.appendChild(p);
}
pre {
  margin: 0;
  padding: 0;
}

Post a Comment for "How To Retry An Xhr Request Which Returns A Promise Recursively For Atleast N Times On Status 0"