分享JavaScript监听全部Ajax请求事件的方法

 更新时间:2016年08月28日 16:22:07   投稿:daisy  
最近在做一个小项目,引入了第三方js文件,这个文件会调用XMLHttpRequest向服务器发送 Ajax请求,但是我有需要监听其Ajax请求的某些事件,以便额外地执行其他脚本。于是稍微看了看监听 Ajax请求的事件方法,在这里分享给大家。有需要的朋友们可以参考借鉴。

若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+ 上愉快地使用了,以上就是本文的全部内容,希望大家能够喜欢。

相关文章

  • JS克隆,属性,数组,对象,函数实例分析

    JS克隆,属性,数组,对象,函数实例分析

    这篇文章主要介绍了JS克隆,属性,数组,对象,函数,结合实例形式分析了javascript中面向对象程序设计相关的对象、属性、函数及数组等相关技巧,需要的朋友可以参考下
    2016-11-11
  • js实现小窗口拖拽效果

    js实现小窗口拖拽效果

    这篇文章主要为大家详细介绍了js实现小窗口拖拽效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • JS数字精度丢失的原因及解决方案

    JS数字精度丢失的原因及解决方案

    JS的数字类型一旦数字超过限值,JS将会丢失精度,导致前后端的值出现不一致,这篇文章主要给大家介绍了关于JS数字精度丢失的原因分析及解决方法,需要的朋友可以参考下
    2022-04-04
  • JavaScript的介绍和简单语法(示例代码)

    JavaScript的介绍和简单语法(示例代码)

    JavaScript是一种广泛使用的脚本语言,为网页添加交互性和动态功能提供了强大的支持,在本文中,我们将深入了解JavaScript的基本概念和用法,包括它在HTML中的书写位置、注释和结束符的使用,以及一种常用的函数——alert语句,感兴趣的朋友一起看看吧
    2023-09-09
  • JavaScript统计字符出现次数

    JavaScript统计字符出现次数

    这篇文章主要为大家详细介绍了JavaScript字符统计出现次数,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-03-03
  • JS实现快速比较两个字符串中包含有相同数字的方法

    JS实现快速比较两个字符串中包含有相同数字的方法

    这篇文章主要介绍了JS实现快速比较两个字符串中包含有相同数字的方法,涉及javascript字符串的遍历、排序、比较等相关操作技巧,需要的朋友可以参考下
    2017-09-09
  • Js利用正则表达式去除字符串的中括号

    Js利用正则表达式去除字符串的中括号

    这篇文章主要给大家介绍了关于Js利用正则表达式去除字符串的中括号的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • Js如何判断客户端是PC还是手持设备简单分析

    Js如何判断客户端是PC还是手持设备简单分析

    在工作过程中,许多朋友会经常用到js判断客户端是PC还是手持设备,今天将提供以下方法,需要的朋友可以参考下
    2012-11-11
  • 微信小程序登录数据解密及状态维持实例详解

    微信小程序登录数据解密及状态维持实例详解

    这篇文章主要介绍了微信小程序登录数据解密及状态维持,结合实例形式分析了微信小程序解密敏感信息及获取session保持登陆状态的相关操作技巧,需要的朋友可以参考下
    2019-05-05
  • JavaScript实现图片合成下载的示例

    JavaScript实现图片合成下载的示例

    这篇文章主要介绍了JavaScript实现图片合成下载的示例,帮助大家更好的理解和学习JavaScript,感兴趣的朋友可以了解下
    2020-11-11

最新评论