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

赞 (0)

相关推荐

  • 详解JavaScript for循环中发送AJAX请求问题

    首先说,出现这个问题的场景是很少见的,因为有太多更好解决方法.今天搞ajax的时候,一个有趣的地方,,每个迭代中都要发送一个get请求,因为迭代的速度太快,一个请求还没有完成就进行下一个迭代,在chrome和ff上,除最后一个请求外,其它请求都被取消了.所以该怎么办呢?设置延时(不太好)还是其他办法?  办法有很多,比如设置休眠,迭代等等, 我采用的是另外两种解决办法.  一.同步的ajax请求,而ajax请求默认是异步的,所以要设置为false. function creatXMLHttpRe

  • jQuery通过Ajax向PHP服务端发送请求并返回JSON数据

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.易于人阅读和编写,同时也易于机器解析和生成.JSON在前后台交互的过程中发挥着相当出色的作用. 服务端PHP读取MYSQL数据,并转换成JSON数据,传递给前端Javascript,并操作JSON数据.本文将通过实例演示了jQuery通过Ajax向PHP服务端发送请求并返回JSON数据.阅读本文的读者应该具备jQuery.Ajax.PHP相关知识,并能熟练运用. XHTML <ul id="use

  • JS 拦截全局ajax请求实例解析

    你是否有过下面的需求:需要给所有ajax请求添加统一签名.需要统计某个接口被请求的次数.需要限制http请求的方法必须为get或post.需要分析别人网络协议等等,那么如何做?想想,如果能够拦截所有ajax请求,那么问题就会变的很简单!

  • 原生 JS Ajax,GET和POST 请求实例代码

    javascript/js的ajax的GET请求代码如下所示: <script type="text/javascript"> /* 创建 XMLHttpRequest 对象 */ var xmlHttp; function GetXmlHttpObject(){ if (window.XMLHttpRequest){ // code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest();

  • js与jQuery终止正在发送的ajax请求的方法

    本文实例讲述了js与jQuery终止正在发送的ajax请求的方法.分享给大家供大家参考,具体如下: 核心:调用XMLHttpRequest对象上的abort方法 jquery的ajax方法有自己的超时时间设置参数: $.ajax({type:'POST', url:'b.php', data:'', timeout:5000, success:function(){ } }) 同时 1. $.get返回的数据类型是XMLHttpRequest,请参考手册.($.post.$.ajax.$.get

  • SpringMVC环境下实现的Ajax异步请求JSON格式数据

    一 环境搭建 首先是常规的spring mvc环境搭建,不用多说,需要注意的是,这里需要引入jackson相关jar包,然后在spring配置文件"springmvc-servlet.xml"中添加json解析相关配置,我这里的完整代码如下: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schem

  • Node.js服务器环境下使用Mock.js拦截AJAX请求的教程

    0.Node环境下安装和使用Mock # 安装 npm install mockjs // 使用 Mock var Mock = require('mockjs') var data = Mock.mock({ // 属性 list 的值是一个数组,其中含有 1 到 10 个元素 'list|1-10': [{ // 属性 id 是一个自增数,起始值为 1,每次增 1 'id|+1': 1 }] }) // 输出结果 console.log(JSON.stringify(data, null,

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

    若Ajax请求是由jQuery的$.ajax发起的,默认情况下可以使用 jQuery的Global Ajax Event Handlers监听到Ajax事件,然而我遇到的却是用原生JavaScript发起的Ajax请求,所以这种方法行不通. 然后呢,还有其他方法,比如说 Pub/Sub,但是这个发起请求的 js 代码我是无法改动的,也就不存在向代码里添加 publish 的问题.同理,jQuery 的 .bind 和 .trigger 也无法使用. 最后,决定使用直接 override XMLH

  • JavaScript监听文本框回车事件并过滤文本框空格的方法

    本文实例讲述了JavaScript监听文本框回车事件并过滤文本框空格的方法.分享给大家供大家参考.具体如下: <script type="text/javascript" language="javascript"> var username = null; var password = null; //获取文本框 onload = function() { username = document.getElementById("txtUser

  • iOS中监听UITextField值改变事件的方法实例

    前言 在实际情况中我们有时候在界面输入时候需要让用户输入的数据与模型同步,那么可能我们就需要监听UITextField值改变事件,然后在响应的方法中将新的值同步到模型中.这次我们主要提出三种方案,其中第一种方案是不一定有效的,后两种方案则是比较可靠的方案. 一.实现UITextFieldDelegate协议. 这种方式实际上是由系统空间回调协议中的方式,并且通过查阅文档我们可以发现有以下相关接口是相关的. - (BOOL)textFieldShouldBeginEditing:(UITextFi

  • 监听element-ui table滚动事件的方法

    背景 做管理平台的项目,用到了element-ui,需要通过监听el-table滚动的位置来获取最新的数据,那么怎么样监听el-table的滚动呢? 准备 我们默认的技术栈是 vue+element-ui template代码: <el-table :data="logList" :show-header="false" row-class-name="table-row-class" height="700" ref=

  • JavaScript 监听textarea中按键事件

    有个textarea, Java代码 复制代码 代码如下: <textarea id="text"></textarea> 经常会定义onKeyPress="keypress();",并定义以下方法. 复制代码 代码如下: var keypress = function(e){ var e = e || window.event; var k = e.keyCode; } 这里我使用的办法是JQuery. 复制代码 代码如下: $("

  • JavaScript监听触摸事件代码实例

    这篇文章主要介绍了JavaScript监听触摸事件代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 监听 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="initial-scale=1, maximum-scale=1, use

  • Layui表格监听行单双击事件讲解

    在学MVC过程中,我们一般都是利用layui插件里的layui数据表格加载数据库中的数据,而layui表格里有许多的事件监听,比如监听行的单双击事件,可利用行的单双击事件实现很多我们想要的功能,比单击某条数据可以进行修改.删除操作,双击某条数据调出到其他表中,接下来就讲讲layui表格里的监听行的单双击事件. 如上图所示:因为这个数据表格用到了layui插件,因此在使用前要先引用layui插件里面的css文件以及js文件,然后在"$(function(){});"里面加载和初始化lay

  • JavaScript监听手机物理返回键的两种解决方法

    JavaScript没有监听物理返回键的API,所以只能使用 popstate 事件监听. 有两个解决办法: 1.返回到指定的页面 pushHistory(); window.addEventListener("popstate", function(e) { window.location = 'http://www.baidu.com'; }, false); function pushHistory() { var state = { title: "title&quo

  • Vue 监听列表item渲染事件方法

    直入正题,不废话! 使用Vue渲染列表是很简单方便的,但如果需要在渲染item的时候去监听事件就无法实现了,楼主我翻遍了Vue的api也没找到合适的方法去解决,其中也提到使用watch和vue.nextClick 监听,但这些都不能实现,苦恼啊,不过机智的我还是想到了曲线救过的方法,利用过滤器来实现,代码如下 <li v-for="item in list"> {{item.content | setEvent item.id , item.name}}</li>

  • JavaScript监听一个DOM元素大小变化

    1.需求场景 开发过程中经常遇到的一个问题就是如何监听一个 div 的size变化. 比如我用canvas绘制了一个chart,当canvas的size发生变化的时候,需要重新绘制里面的内容,这个时候就需要监听resize事件做处理.window上虽然有resize事件监听,但这并不能满足我们的需求,因为很多时候,div的size发生了变化,实际 window.resize 事件并未触发. 对于div的resize事件的监听,实现方式有很多,比如定时器检查,通过scroll事件等等,本文主要介绍

随机推荐