javascript学习指南|JavaScript监听全部Ajax请求的事件详解

时间:2020-11-06  来源:js教程  阅读:


最近博主在做一个小项目,引入了第三方 js 文件,这个文件会调用 XMLHttpRequest 向服务器发送 Ajax 请求,但是我有需要监听其 Ajax 请求的某些事件,以便额外地执行其他脚本。于是,稍微看了看监听 Ajax 请求的事件方法,在这里分享给大家。

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

然后呢,还有其他方法,比如说 Pub/Sub,也就是 ps://github.com/cowboy/jquery-tiny-pubsub">https://github.com/cowboy/jquery-tiny-pubsub 这个 jQuery 插件,但是这个发起请求的 js 代码我是无法改动的,也就不存在向代码里添加 publish 的问题。同理,jQuery 的 .bind 和 .trigger 也无法使用。

最后,决定使用直接 override XMLHttpRequest,同时配合使用自定义事件。


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

show source
这个解决方案,无法监听全部的 XHR Events ,而且 readystatechange 事件是在调用 send 方法后才监听,也就无法监听到 readyState = 1 时的事件。同时,如果在使用 send 方法后再对 onreadystatechange 设置回调函数,会将 override 的代码又一次 override,也就无法产生预想的效果。
 

那如何才能正确地 override XHR 呢?贴上代码,留你小命:

;(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); // XMLHttpRequest Object
});
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+ 上愉快地使用了,caniuse。

javascript学习指南|JavaScript监听全部Ajax请求的事件详解

http://m.bbyears.com/wangyezhizuo/109052.html

推荐访问:
相关阅读 猜你喜欢
本类排行 本类最新