JavaScript監聽全部Ajax請求的事件詳解

來源:互聯網
上載者:User


最近博主在做一個小項目,引入了第三方 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。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.