Skip to content

Instantly share code, notes, and snippets.

@suprememoocow
Created May 29, 2012 09:53
Show Gist options
  • Select an option

  • Save suprememoocow/2823600 to your computer and use it in GitHub Desktop.

Select an option

Save suprememoocow/2823600 to your computer and use it in GitHub Desktop.
AJAX timing interceptor: this class intercepts all AJAX calls and records the time taken for the HTTP request to complete. These timings are posted back to the server in batches, if there are any to send, about every two seconds. Tested in Firefox, Chrome
(function(XHR) {
"use strict";
var stats = [];
var timeoutId = null;
var open = XHR.prototype.open;
var send = XHR.prototype.send;
XHR.prototype.open = function(method, url, async, user, pass) {
this._url = url;
open.call(this, method, url, async, user, pass);
};
XHR.prototype.send = function(data) {
var self = this;
var start;
var oldOnReadyStateChange;
var url = this._url;
function onReadyStateChange() {
if(self.readyState == 4 /* complete */) {
var time = new Date() - start;
stats.push({
url: url,
duration: time
});
if(!timeoutId) {
timeoutId = window.setTimeout(function() {
var xhr = new XHR();
xhr.noIntercept = true;
xhr.open("POST", "/clientAjaxStats", true);
xhr.setRequestHeader("Content-type","application/json");
xhr.send(JSON.stringify({ stats: stats } ));
timeoutId = null;
stats = [];
}, 2000);
}
}
if(oldOnReadyStateChange) {
oldOnReadyStateChange();
}
}
if(!this.noIntercept) {
start = new Date();
if(this.addEventListener) {
this.addEventListener("readystatechange", onReadyStateChange, false);
} else {
oldOnReadyStateChange = this.onreadystatechange;
this.onreadystatechange = onReadyStateChange;
}
}
send.call(this, data);
}
})(XMLHttpRequest);
@wenzuojing

Copy link
Copy Markdown

Ie 6 does not support the XMLHttpRequest object, how should solve? Thank you !

@shishirarora3

Copy link
Copy Markdown

arey if XHR is not supported then do the same thing with whatever is supported

@ashishsajwan

Copy link
Copy Markdown

@suprememoocow try using performance.now() instead of new Date()

@thang-hoang

Copy link
Copy Markdown

very nice and elegant, applying to my project now 👍

@kundank010

Copy link
Copy Markdown

Can anyone help me, I'm not getting how to use intercept.js.

@llloyola

Copy link
Copy Markdown

I'm kind of new to javascript
Could anyone help me to understand how to use this?

@bernardoadc

Copy link
Copy Markdown

@Rkundan, @llloyola
Just load the file / execute in console. Every time an AJAX call is made, the code will trigger. Specifically in line 34, he's setting to send AJAX information to own server URL "/clientAjaxStats". This should be modified to your needs

@sourcecodeit

Copy link
Copy Markdown

I'm kind of new to javascript
Could anyone help me to understand how to use this?

No, please you explain why you'd need this being new to JS :) really, just curious!

@p3v9d5ui

Copy link
Copy Markdown

@suprememoocow , should this work in all cases? Or it is possible that some code uses a different method to fetch data, and therefore bypass this? I've been experimenting with this, and find that it only works in some cases, but I have not been able to discover why.

@dominikj111

dominikj111 commented Oct 19, 2022

Copy link
Copy Markdown

Thank you for such a nice code. I did couple changes to match my needs.

(function (XHR) {
	"use strict";

	var open = XHR.prototype.open;
	var send = XHR.prototype.send;
	var setRequestHeader = XHR.prototype.setRequestHeader;

	var interceptBefore = [];
	var interceptAfter = [];
	var requestHeaders = {};

	XHR.prototype.setRequestHeader = function (header, value) {
		requestHeaders[header] = value;
		setRequestHeader.call(this, header, value);
	};

	XHR.prototype.open = function (method, url, async, user, pass) {
		this._url = url;
		this._method = method;
		open.call(this, method, url, async, user, pass);
	};

	XHR.prototype.send = function (data) {
		var self = this;
		var primeOnReadyStateChange = this.onReadyStateChange;

		for (var i = 0; i < interceptBefore.length; i += 1) {
			interceptBefore[i].apply(null, [
				this,
				decodeURIComponent(data),
				decodeURIComponent(this._url),
				this._method.toLocaleLowerCase(),
				requestHeaders,
			]);
		}

		function onReadyStateChange() {
			if (self.readyState == 4 /* complete */) {
				for (var i = 0; i < interceptAfter.length; i += 1) {
					interceptAfter[i](self);
				}
			}

			if (primeOnReadyStateChange) {
				primeOnReadyStateChange();
			}
		}

		if (this.addEventListener) {
			this.addEventListener(
				"readystatechange",
				onReadyStateChange,
				false
			);
		} else {
			this.onreadystatechange = onReadyStateChange;
		}

		send.call(this, data);
	};

	XHR.interceptBefore = function (callback) {
		interceptBefore.push(callback);
	};

	XHR.interceptAfter = function (callback) {
		interceptAfter.push(callback);
	};
})(XMLHttpRequest);

The example:

XMLHttpRequest.interceptBefore((XHR, data, url, method, requestHeaders) => {
	console.log("BEFORE: ");
	console.log(XHR);
	console.log(method);
	console.log(data);
	console.log(url);
	console.log(requestHeaders);
});

XMLHttpRequest.interceptAfter((XHR) => {
	console.log(
		"AFTER: ",
		XHR,
		XHR.getAllResponseHeaders()
			.split("\r\n")
			.filter(Boolean)
			.reduce(
				(acc, x) => ({ ...acc, [x.split(": ")[0]]: x.split(": ")[1] }),
				{}
			),
		XHR.responseURL,
		XHR.responseText
	);
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment