您的位置:首页 > Web前端 > JavaScript

分享JavaScript监听全部Ajax请求事件的方法

2016-08-28 16:22 627 查看

若Ajax请求是由jQuery的

$.ajax
发起的,默认情况下可以使用 jQuery的Global Ajax Event Handlers监听到Ajax事件,然而我遇到的却是用原生JavaScript发起的Ajax请求,所以这种方法行不通。

然后呢,还有其他方法,比如说 Pub/Sub,但是这个发起请求的 js 代码我是无法改动的,也就不存在向代码里添加 publish 的问题。同理,jQuery 的

.bind
.trigger
也无法使用。

最后,决定使用直接

overrideXMLHttpRequest
,同时配合使用自定义事件。 

在 StackOverflow 上搜索,发现有个歪果仁给出了一个不靠谱的解决方法,嗯,贴出来给大家看看:

;(function () {
var open = window.XMLHttpRequest.prototype.open,
send= window.XMLHttpRequest.prototype.send,
onReadyStateChange;
function openReplacement(method, url, async, user, password) {
// some code
return open.apply(this, arguments);
}
function sendReplacement(data) {
// some code
if(this.onreadystatechange) this._onreadystatechange= this.onreadystatechange;
this.onreadystatechange= onReadyStateChangeReplacement;
return send.apply(this, arguments);
}
function onReadyStateChangeReplacement() {
// some code
if (this._onreadystatechange) return this._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() {
function ajaxEventTrigger(event) {
var ajaxEvent = new CustomEvent(event, { detail: this });
window.dispatchEvent(ajaxEvent);
}
var oldXHR= window.XMLHttpRequest;
function newXHR() {
var realXHR= new oldXHR();
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);
return realXHR;
}
window.XMLHttpRequest= newXHR;
})();

这样,就为

XHR
添加了自定义事件。如何调用?

var xhr = new XMLHttpRequest();
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 下,甚至连 IE 11 都不支持,所以需要加上
Polyfill
,变成这样:

;(function () {
if ( typeof window.CustomEvent=== "function" ) return false;
function CustomEvent( event, params ) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent( 'CustomEvent' );
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
return evt;
}
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent= CustomEvent;
})();
;(function () {
function ajaxEventTrigger(event) {
var ajaxEvent = new CustomEvent(event, { detail: this });
window.dispatchEvent(ajaxEvent);
}
var oldXHR= window.XMLHttpRequest;
function newXHR() {
var realXHR= new oldXHR();
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);
return realXHR;
}
window.XMLHttpRequest= newXHR;
})();

此时,就可以在 IE 9+、Chrome 15+、FireFox 11+、Edge、Safari 6.1+、Opera 12.1+ 上愉快地使用了,以上就是本文的全部内容,希望大家能够喜欢。

您可能感兴趣的文章:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息