【轉】分享JavaScript監聽所有Ajax請求事件的方法

若Ajax請求是由jQuery的$.ajax發起的,默認狀況下可使用 jQuery的Global Ajax Event Handlers監聽到Ajax事件,然而我遇到的倒是用原生JavaScript發起的Ajax請求,因此這種方法行不通。javascript

而後呢,還有其餘方法,好比說 Pub/Sub,可是這個發起請求的 js 代碼我是沒法改動的,也就不存在向代碼裏添加 publish 的問題。同理,jQuery 的 .bind 和 .trigger 也沒法使用。java

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

在 StackOverflow 上搜索,發現有個歪果仁給出了一個不靠譜的解決方法,嗯,貼出來給你們看看:json

  

;(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 呢?貼上代碼,一塊兒來看看:app

;(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 添加了自定義事件。如何調用?async

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.responseTextide

同時,addEventListener 方法必須掛載在 window 對象上,而不能是 XHR 實例上。 函數

由於以上代碼使用了 CustomEvent 構造函數,在現代瀏覽器上能夠正常使用,可是在 IE 下,甚至連 IE 11 都不支持,因此須要加上 Polyfill,變成這樣:this

;(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+ 上愉快地使用了,以上就是本文的所有內容,但願你們可以喜歡。

from:https://www.jb51.net/article/91419.htm

相關文章
相關標籤/搜索