3

In my javascript file for a page, I would like to execute some scripts after all the XHR have returned. I know that there is ajaxStop() for XHR requests through jquery, but since I am using Mithril and it has its own wrapper around Ajax, I can't really use ajaxStop(). I have also tried some other solutions like

function isAllXhrComplete(){
    window.activeAjaxCount--;
    if (window.activeAjaxCount === 0){
        //execute something here.
    }

}

(function(open) {
    XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
        this.addEventListener("load", isAllXhrComplete());
        open.call(this, method, url, async, user, pass);
    };
})(XMLHttpRequest.prototype.open);


(function(send) {
    XMLHttpRequest.prototype.send = function (data) {
        window.activeAjaxCount++;
        send.call(this, data);
    };
})(XMLHttpRequest.prototype.send);

But it seems that since all the XHR calls are fired separately, the window.activeAjaxCount would always be 1 or 0, thus triggering the execution of script on every finished XHR request.

Is there any good ways to wait for all XHR requests to return?

ciscoheat
  • 3,412
  • 1
  • 28
  • 47
adlius45
  • 41
  • 4
  • It is probably a duplicate to [Calling functions with setTimeout()](http://stackoverflow.com/questions/3800512/calling-functions-with-settimeout). Even though it is about `setTimeout` the reason is still the same. – t.niese Jul 19 '16 at 15:14
  • 1
    While one problem is that you're calling `isAllXhrComplete()` instead of passing it, I really wouldn't overwrite the original methods to do what you want. You can do this by creating a function that manages a group of XHR calls. –  Jul 19 '16 at 15:14

1 Answers1

3

Your mistake is here:

this.addEventListener("load", isAllXhrComplete());

the isAllXhrComplete is not passed as callback, because you immediately call it. Instead the result of the isAllXhrComplete() call is passed.

You have to write:

this.addEventListener("load", isAllXhrComplete);

Beside that you should really take care when you wrap existing functions. A correct way would be:

(function(send) {
   XMLHttpRequest.prototype.send = function () {
      window.activeAjaxCount++;
      return send.apply(this, arguments);
   };
})(XMLHttpRequest.prototype.send);

The important part is that you return the result of the original function, and that you use apply to pass all possible arguments. Otherwise you might break code in future, if the signature of those functions is changed.

Your need to do the same with the open wrapper:

(function(open) {
  XMLHttpRequest.prototype.open = function() {
    this.addEventListener("load", isAllXhrComplete);
    return open.apply(this, arguments);
  };
})(XMLHttpRequest.prototype.open);
t.niese
  • 32,069
  • 7
  • 56
  • 86