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

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

【转】分享JavaScript监听全部Ajax请求事件的方法的更多相关文章

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

    JavaScript没有监听物理返回键的API,所以只能使用 popstate 事件监听. 有两个解决办法: 1.返回到指定的页面 pushHistory(); window.addEventList ...

  2. 解决Fiddler不能监听Java HttpURLConnection请求的方法

    在默认情况下,Fiddler不能监听Java HttpURLConnection请求.究其原因,Java的网络通信协议栈可能浏览器的通信协议栈略有区别,Fiddler监听Http请求的原理是 在应用程 ...

  3. javascript监听手机返回键

    javascript监听手机返回键 <pre> if (window.history && window.history.pushState) { $(window).on ...

  4. 使用Fiddler监听java HttpURLConnection请求

    使用Fiddler监听java HttpURLConnection请求

  5. JavaScript监听回车事件

    记录一下,兼容性也考虑到了,原文地址:JavaScript 监听回车事件 JS监听某个输入框 //回车事件绑定 $('#search_input').bind('keyup', function(ev ...

  6. JavaScript监听页面可见性(焦点)同时改变title的三种方法

    JavaScript监听页面可见性(焦点)同时改变title的三种方法 本文参考了https://developer.mozilla.org/zh-CN/docs/Web/API/Page_Visib ...

  7. JavaScript 监听回车事件

    JS监听某个输入框 //回车事件绑定 $('#search_input').bind('keyup', function(event) { if (event.keyCode == "13& ...

  8. 微信浏览器返回刷新,监听微信浏览器返回事件,网页防复制,移动端禁止图片长按和vivo手机点击img标签放大图片

    以下代码都经过iphone7,华为MT7 ,谷歌浏览器,微信开发者工具,PC端微信验证.如有bug,还请在评论区留言. demo链接:https://pan.baidu.com/s/1c35mbjM ...

  9. C# 动态创建SQL数据库(二) 在.net core web项目中生成二维码 后台Post/Get 请求接口 方式 WebForm 页面ajax 请求后台页面 方法 实现输入框小数多 自动进位展示,编辑时实际值不变 快速掌握Gif动态图实现代码 C#处理和对接HTTP接口请求

    C# 动态创建SQL数据库(二) 使用Entity Framework  创建数据库与表 前面文章有说到使用SQL语句动态创建数据库与数据表,这次直接使用Entriy Framwork 的ORM对象关 ...

随机推荐

  1. Java小白如何一步步学好Java,听听企业Java培训师的实践经验吧

    今天我准备给小主展示一篇Java培训老师的文章,希望能给Java小白一个学好Java的路径或者提示.以下就是原文: 从大学到现在,我使用Java已经将近20年,日常也带实习生,还在公司内部做train ...

  2. CAS机制与自旋锁

    CAS(Compare-and-Swap),即比较并替换,java并发包中许多Atomic的类的底层原理都是CAS. 它的功能是判断内存中某个地址的值是否为预期值,如果是就改变成新值,整个过程具有原子 ...

  3. Leetcode 题解

    Leetcode Solutions Language: javascript c mysql Last updated: 2019-01-04 https://github.com/nusr/lee ...

  4. Java基础——集合(持续更新中)

    集合框架 Java.util.Collection Collection接口中的共性功能 1,添加 booblean add(Object obj);  往该集合中添加元素,一次添加一个 boolea ...

  5. 【视频】Entity Framework Core 2.* 入门教程

    视频专辑在B站上:https://www.bilibili.com/video/av34462368/ 内容暂时如下,还在更新中: 1. 简介 & 创建Model,生成数据库 2. 在ASP. ...

  6. Accept 与 Content-Type

    Accept 表示请求方希望的资源类型,或者能解析识别的类型 Content-Type 表示实际发送的资源类型 这里资源类型通过 MIME types 表示. Accept Accept 是浏览器发送 ...

  7. knockoutjs data-bind 声明式绑定整理

    一.Visible绑定 1.功能 Visible绑定通过绑定一个值来确定DOM元素显示或隐藏 2.示例 <div data-bind="visible: shouldShowMessa ...

  8. ASP.NET Core - 从Program和Startup开始

    Program 我们先看一下1.x和2.x的程序入口项的一个差异 1.x public class Program { public static void Main(string[] args) { ...

  9. ES6躬行记(21)——类的继承

    ES6的继承依然是基于原型的继承,但语法更为简洁清晰.通过一个extends关键字,就能描述两个类之间的继承关系(如下代码所示),在此关键字之前的Man是子类(即派生类),而在其之后的People是父 ...

  10. kubernetes系列12—二个特色的存储卷configmap和secret

    本文收录在容器技术学习系列文章总目录 1.configmap 1.1 认识configmap ConfigMap用于保存配置数据的键值对,可以用来保存单个属性,也可以用来保存配置文件.ConfigMa ...