分享JavaScript監聽全部Ajax請求事件的方法_javascript技巧

來源:互聯網
上載者:User

若Ajax請求是由jQuery的$.ajax發起的,預設情況下可以使用 jQuery的Global Ajax Event Handlers監聽到Ajax事件,然而我遇到的卻是用原生JavaScript發起的Ajax請求,所以這種方法行不通。

然後呢,還有其他方法,比如說 Pub/Sub,但是這個發起請求的 js 代碼我是無法改動的,也就不存在向代碼裡添加 publish 的問題。同理,jQuery 的 .bind.trigger 也無法使用。

最後,決定使用直接 override XMLHttpRequest,同時配合使用自訂事件。 

在 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;})();

這個解決方案,無法監聽全部的 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 返回的 eXMLHttpRequest 對象,但是自訂方法 ajaxReadyStateChange 等事件 handler 返回的 eCustomEvent 對象,而 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+ 上愉快地使用了,以上就是本文的全部內容,希望大家能夠喜歡。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.