GibboK GibboK - 5 months ago 55
Ajax Question

How to set up a timeout and ontimeout for XMLHttpRequest?

At the moment I am using a similar code visible below to set a specific value for

timeout
when creating an instance of
XMLHttpRequest
.
I also set a function for
ontimeout
which will be executed when event is fired.

I would like to know if it is possible to set a
timeout
value globally for any
XMLHttpRequest
and a global function when
ontimeout
is called.

I am aware I could use a factory for
XMLHttpRequest
which could set
timeout
and
ontimeout
automatically on each instance created but I would like to know if a different approach exists.

Notes: I am looking for a solution based on vanilla JavaScript (no jQuery or other libraries) and I am targeting only Chrome and FireFox latest version.

Any idea is welcome thanks.

var xhr = new XMLHttpRequest();
xhr.open('GET', '/server', true);
xhr.timeout = 2000;
xhr.onload = function () {};
xhr.ontimeout = function (e) {
// do smt here
};
xhr.send(null);

Answer

You have at least three options:

  1. Encapsulate your use of XMLHttpRequest in your own function. That lets you apply these sorts of things in that function. The fact your code uses the function makes it perfectly clear what's going on. For instance:

    function createXHR() {
        var xhr = new XMLHttpRequest();
        xhr.timeout = 2000;  
        xhr.addEventListener("timeout", function(e) {
            // ...
        });
        return xhr;
    }
    
  2. Override XMLHttpRequest with your own version. I do not recommend doing this, but sometimes if you need to integrate with code that uses XMLHttpRequest directly, you may feel you need to do it. Example:

    (function() {
        var realXMLHttpRequest = XMLHttpRequest;
        XMLHttpRequest = function fakeXMLHttpRequest() {
            realXMLHttpRequest.apply(this, arguments);
            this.timeout = 2000;  
            this.addEventListener("timeout", function(e) {
                // ...
            });
        };
        XMLHttpRequest.prototype = realXMLHttpRequest.prototype;
    })();
    

    Again, I do not recommend it, but it's possible.

    You've said below that the one above doesn't work for you. If it doesn't, it's because the XMLHttpRequest implementation you're using is making life difficult. This workaround will work:

    (function() {
        var realXMLHttpRequest = XMLHttpRequest;
        XMLHttpRequest = function fakeXMLHttpRequest(arg) {
            var xhr;
            if (typeof arg !== "undefined") {
                // Some implementations allow for a non-standard argument, support them
                xhr = new realXMLHttpRequest(arg);
            } else {
                // Normal case
                xhr = new realXMLHttpRequest();
            }
            xhr.timeout = 2000;  
            xhr.addEventListener("timeout", function(e) {
                // ...
            });
            return xhr;
        };
        XMLHttpRequest.prototype = realXMLHttpRequest.prototype;
    })();
    

    That works even though you call it with new XMLHttpRequest because the way the new operator works is that it creates an object and calls the function with that object as this, and then the result of new is that object unless the function returns a different non-null object, as the one above does.

    Did I mention I do not recommend this? ;-)

  3. Use a library that already does #1 for you.