分享JavaScript监听全部Ajax请求事件的方法
若Ajax请求是由jQuery的$.ajax发起的,默认情况下可以使用jQuery的GlobalAjaxEventHandlers监听到Ajax事件,然而我遇到的却是用原生JavaScript发起的Ajax请求,所以这种方法行不通。
然后呢,还有其他方法,比如说Pub/Sub,但是这个发起请求的js代码我是无法改动的,也就不存在向代码里添加publish的问题。同理,jQuery的.bind和.trigger也无法使用。
最后,决定使用直接overrideXMLHttpRequest,同时配合使用自定义事件。
在StackOverflow上搜索,发现有个歪果仁给出了一个不靠谱的解决方法,嗯,贴出来给大家看看:
;(function(){
varopen=window.XMLHttpRequest.prototype.open,
send=window.XMLHttpRequest.prototype.send,
onReadyStateChange;
functionopenReplacement(method,url,async,user,password){
//somecode
returnopen.apply(this,arguments);
}
functionsendReplacement(data){
//somecode
if(this.onreadystatechange)this._onreadystatechange=this.onreadystatechange;
this.onreadystatechange=onReadyStateChangeReplacement;
returnsend.apply(this,arguments);
}
functiononReadyStateChangeReplacement(){
//somecode
if(this._onreadystatechange)returnthis._onreadystatechange.apply(this,arguments);
}
window.XMLHttpRequest.prototype.open=openReplacement;
window.XMLHttpRequest.prototype.send=sendReplacement;
})();
这个解决方案,无法监听全部的XHREvents,而且readystatechange事件是在调用send方法后才监听,也就无法监听到readyState=1时的事件。同时,如果在使用send方法后再对onreadystatechange设置回调函数,会将override的代码又一次override,也就无法产生预想的效果。
那如何才能正确地overrideXHR呢?贴上代码,一起来看看:
;(function(){
functionajaxEventTrigger(event){
varajaxEvent=newCustomEvent(event,{detail:this});
window.dispatchEvent(ajaxEvent);
}
varoldXHR=window.XMLHttpRequest;
functionnewXHR(){
varrealXHR=newoldXHR();
realXHR.addEventListener('abort',function(){ajaxEventTrigger.call(this,'ajaxAbort');},false);
realXHR.addEventListener('error',function(){ajaxEventTrigger.call(this,'ajaxError');},false);
realXHR.addEventListener('load',function(){ajaxEventTrigger.call(this,'ajaxLoad');},false);
realXHR.addEventListener('loadstart',function(){ajaxEventTrigger.call(this,'ajaxLoadStart');},false);
realXHR.addEventListener('progress',function(){ajaxEventTrigger.call(this,'ajaxProgress');},false);
realXHR.addEventListener('timeout',function(){ajaxEventTrigger.call(this,'ajaxTimeout');},false);
realXHR.addEventListener('loadend',function(){ajaxEventTrigger.call(this,'ajaxLoadEnd');},false);
realXHR.addEventListener('readystatechange',function(){ajaxEventTrigger.call(this,'ajaxReadyStateChange');},false);
returnrealXHR;
}
window.XMLHttpRequest=newXHR;
})();
这样,就为XHR添加了自定义事件。如何调用?
varxhr=newXMLHttpRequest();
window.addEventListener('ajaxReadyStateChange',function(e){
console.log(e.detail);//XMLHttpRequestObject
});
window.addEventListener('ajaxAbort',function(e){
console.log(e.detail.responseText);//XHR返回的内容
});
xhr.open('GET','info.json');
xhr.send();
需要注意的是,正常的readystatechange等事件handler返回的e是XMLHttpRequest对象,但是自定义方法ajaxReadyStateChange等事件handler返回的e是CustomEvent对象,而e.detail才是真正的XMLHttpRequest对象。而获得Ajax请求返回内容的e.responseText也需要修改为e.detail.responseText。
同时,addEventListener方法必须挂载在window对象上,而不能是XHR实例上。
因为以上代码使用了CustomEvent构造函数,在现代浏览器上可以正常使用,但是在IE下,甚至连IE11都不支持,所以需要加上Polyfill,变成这样:
;(function(){
if(typeofwindow.CustomEvent==="function")returnfalse;
functionCustomEvent(event,params){
params=params||{bubbles:false,cancelable:false,detail:undefined};
varevt=document.createEvent('CustomEvent');
evt.initCustomEvent(event,params.bubbles,params.cancelable,params.detail);
returnevt;
}
CustomEvent.prototype=window.Event.prototype;
window.CustomEvent=CustomEvent;
})();
;(function(){
functionajaxEventTrigger(event){
varajaxEvent=newCustomEvent(event,{detail:this});
window.dispatchEvent(ajaxEvent);
}
varoldXHR=window.XMLHttpRequest;
functionnewXHR(){
varrealXHR=newoldXHR();
realXHR.addEventListener('abort',function(){ajaxEventTrigger.call(this,'ajaxAbort');},false);
realXHR.addEventListener('error',function(){ajaxEventTrigger.call(this,'ajaxError');},false);
realXHR.addEventListener('load',function(){ajaxEventTrigger.call(this,'ajaxLoad');},false);
realXHR.addEventListener('loadstart',function(){ajaxEventTrigger.call(this,'ajaxLoadStart');},false);
realXHR.addEventListener('progress',function(){ajaxEventTrigger.call(this,'ajaxProgress');},false);
realXHR.addEventListener('timeout',function(){ajaxEventTrigger.call(this,'ajaxTimeout');},false);
realXHR.addEventListener('loadend',function(){ajaxEventTrigger.call(this,'ajaxLoadEnd');},false);
realXHR.addEventListener('readystatechange',function(){ajaxEventTrigger.call(this,'ajaxReadyStateChange');},false);
returnrealXHR;
}
window.XMLHttpRequest=newXHR;
})();
此时,就可以在IE9+、Chrome15+、FireFox11+、Edge、Safari6.1+、Opera12.1+上愉快地使用了,以上就是本文的全部内容,希望大家能够喜欢。