Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
388 views
in Technique[技术] by (71.8m points)

javascript - Recreating jQuery's ajaxStart and ajaxComplete functionality

I'm trying to reproduce jQuery's functions ajaxComplete and ajaxStart without jQuery so that they could be used in any environment with no library dependencies (it's a special use case). These functions allow for an event listener to be called before and after any ajax request. In my example, I call them preAjaxListener and postAjaxListener.

I'm trying to accomplish it by hooking into the XMLHttpRequest object and overwriting/decorating open and send. Yes, I know this is dirty.

XMLHttpRequest.prototype.open = (function(orig){
    return function(a,b,c){
        this._HREF = b; // store target url
        return orig.apply(this, arguments); // call original 'open' function
    };
})(XMLHttpRequest.prototype.open);

XMLHttpRequest.prototype.send = (function(orig){
    return function(){
        var xhr = this;
        _core._fireAjaxEvents('pre', xhr._HREF); // preAjaxListener fires

        var rsc = xhr.onreadystatechange || function(){}; // store the original onreadystatechange if it exists
        xhr.onreadystatechange = function(){ // overwrite with custom function
            try {
                if (xhr.readyState == 4){
                    _core._fireAjaxEvents('post', xhr._HREF); // postAjaxListneer should fire
                    this.onreadystatechange = rsc;
                } 
            } catch (e){ }
            return rsc.apply(this, arguments); // call original readystatechange function
        };

        return orig.apply(this, arguments); // call original 'send' function
    };
})(XMLHttpRequest.prototype.send);

I do not want to write wrapper functions to make ajax requests. I want to be able to hook into any ajax request made by any library (or with vanilla js) on the page.

So far, only the preAjaxListener function works. I can't seem to figure out why, but it seems that onreadystatechange is never being called. Any guidance would be greatly appreciated.

Working demo: http://jsfiddle.net/_nderscore/QTQ5s/

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Using .onreadystatechange wasn't working because I was testing with jQuery and jQuery's ajax methods manipulate and removes the onreadystatechange property.

However, adding an event listener for loadend works just fine everywhere but IE. For IE, I set up an interval instead - not the optimal solution, but it works for my needs. I only intended this script to work on IE8+ and modern browsers.

XMLHttpRequest.prototype.send = (function(orig){
    return function(){
        _core._fireAjaxEvents('pre', this._HREF);

        if (!/MSIE/.test(navigator.userAgent)){
            this.addEventListener("loadend", function(){
                _core._fireAjaxEvents('post', this._HREF);
            }, false);
        } else {
            var xhr = this,
            waiter = setInterval(function(){
                if(xhr.readyState && xhr.readyState == 4){
                    _core._fireAjaxEvents('post', xhr._HREF);
                    clearInterval(waiter);
                }
            }, 50);
        }

        return orig.apply(this, arguments);
    };
})(XMLHttpRequest.prototype.send);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...