最近在做一个项目,其中需要监听页面中不可控代码调用 ajax
请求的事件,比如说监听调用 XHR
后的 onreadystatechange
、onload
、onloadstart
等事件。
嗯,主要是用原生的 JavaScript 实现。查了挺多资料的,大概的做法是:
1、Pub/Sub
,也就是 https://github.com/cowboy/jquery-tiny-pubsub 这个 jQuery
插件。但是因为调用 ajax
请求的代码不可控,无法添加 publish
,或者说我不会添加?
2、jQuery
的 bind
和 trigger
,同上,代码不可控
3、如果是用 jQuery
实现的,可以直接监听其 ajaxCompete
等事件,然而调用 ajax
请求的并不是 jQuery
的 $.ajax
,故此招没用
4、如果 ajax
的回调涉及到 DOM
操作,还可以使用 MutationObserver
,但是最多只能知道 ajax
成功并且更新了 DOM
,不能监听到 onreadystatechange
等事件
5、直接重写 XHR
,配合 CustomEvent
实现
那些已被弃用或降级的方法不作考虑。
针对第五点,查找到了国外相关资料,其做法见如下代码
var open = window.XMLHttpRequest.prototype.open,
send = window.XMLHttpRequest.prototype.send,
ReadyStateChange;
function openReplacement(method, url, async, user, password) {
open.apply(this, arguments);
}
function sendReplacement(data) {
var ajaxReadyStateChange,
ajaxLoad;
console.warn('Sending HTTP request data : ', data);
// onreadystatechange replacement
if (this.onreadystatechange) {
ReadyStateChange = this.onreadystatechange;
}
this.onreadystatechange = function () {
console.warn('HTTP request ready state changed : ' + this.readyState);
ajaxReadyStateChange = new CustomEvent('ajaxReadyStateChange', { detail: this });
window.dispatchEvent(ajaxReadyStateChange);
if(ReadyStateChange) {
ReadyStateChange.apply(this, arguments);
}
// onload
if (this.readyState === 4) {
ajaxLoad = new CustomEvent('ajaxLoad', { detail: this });
dispatchEvent(ajaxLoad);
}
};
send.apply(this, arguments);
}
window.XMLHttpRequest.prototype.open = openReplacement;
window.XMLHttpRequest.prototype.send = sendReplacement;
但是问题在于,onreadystatechange
事件在调用 send
方法时才被绑定,所以无法监听到 readyState
的 0
和 1
状态。而且如果不可控代码中绑定如 onreadystatechange
事件时在调用 send
方法之后,就会使得重写的事件失效。直接 this.addEventListener
没试过。
所以我想直接添加类似于下面这样的代码,当然下面的肯定没用:
window.XMLHttpRequest.onload = function () {
alert('')
}
做到所有 ajax
在触发其事件前,先执行我重写的函数,不知能否实现?
若调用 ajax
的是 $.ajax
,除了上面我提到的,还有什么实现方法?
望赐教,谢谢