If the Ajax request is initiated by jQuery's $.ajax , by default, you can use jQuery's Global Ajax Event Handlers to listen to the Ajax event. However, what I encountered was an Ajax request initiated with native JavaScript, so this method does not work.
Then, there are other methods, such as Pub/Sub, but I cannot change the js code that initiates the request, so there is no problem of adding publish to the code. Similarly, jQuery's .bind and .trigger cannot be used.
Finally, I decided to use the direct override XMLHttpRequest while using custom events.
Searching on StackOverflow, I found that a bad guy gave an unreliable solution. Well, I will post it for you to see:
;(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;})(); This solution cannot listen to all XHR Events , and the readystatechange event is only listened after calling the send method, so it cannot listen to events when readyState = 1 . At the same time, if you set a callback function for onreadystatechange after using the send method, the override code will be override again, and the expected effect will not be produced.
So how can I correctly override XHR? Post the code and let’s take a look:
;(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('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;})(); This way, a custom event is added to XHR . How to call?
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); // content returned by XHR}); xhr.open('GET', 'info.json');xhr.send(); It should be noted that e returned by the normal readystatechange and other event handler is the XMLHttpRequest object, but e returned by the custom method ajaxReadyStateChange and other event handler is the CustomEvent object, and e.detail is the real XMLHttpRequest object. e.responseText that obtains the content returned by the Ajax request also needs to be modified to e.detail.responseText .
At the same time, addEventListener method must be mounted on window 对象, not on XHR instance.
Because the above code uses the CustomEvent constructor, it can be used normally in modern browsers, but under IE, even IE 11 does not support it, so Polyfill needs to be added, which becomes like 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('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;})();At this time, you can use it happily on IE 9+, Chrome 15+, FireFox 11+, Edge, Safari 6.1+, and Opera 12.1+. The above is all the content of this article. I hope you like it.