Wednesday, October 3rd, 2007

Optimized Speedy Ajax Code

Category: Ajax, JavaScript, Tip

Dustin Diaz has revisited his seven JavaScript techniques and has updated his XHR-getting-function to be faster, using the Lazy Function Definition Pattern, which ends up looking like:

var asyncRequest = function() {
function handleReadyState(o, callback) {
if (o && o.readyState == 4 && o.status == 200) {
if (callback) {
var getXHR = function() {
var http;
try {
http = new XMLHttpRequest;
getXHR = function() {
return new XMLHttpRequest;
catch(e) {
var msxml = [
for (var i=0, len = msxml.length; i < len; ++i) { try { http = new ActiveXObject(msxml[i]); getXHR = function() { return new ActiveXObject(msxml[i]); }; break; } catch(e) {} } } return http; }; return function(method, uri, callback, postData) { var http = getXHR();, uri, true); handleReadyState(http, callback); http.send(postData || null); return http; }; }(); [/javascript]

Posted by Dion Almaer at 8:53 am

3.8 rating from 38 votes


Comments feed TrackBack URI

Useless there is little overhead in creating the correct XHR and loading the data over HTTP. There is much more effective result in optimizing the parsing of JSON / XML / etc.

Comment by TimD — October 3, 2007

Ignoring the lazy pattern for a minute, why can’t the XHR object be retrieved with simply:

if (window.XMLHttpRequest)
return new window.XMLHttpRequest();
else if (window.ActiveXObject)
return new ActiveXObject(“Microsoft.XMLHTTP”);

This what I have used for a long time without any problems. I don’t understand why frameworks must use a try/catch (try/catchs are usually not very fast, and very annoying with Firebug). And why the different ActiveXObjects, the MS specs seem to make it clear that you don’t need to do that (the code above should always resolve to the latest version)? Is this just case of code that has been copied time and time again without question?

Comment by Kris Zyp — October 3, 2007

In fact, try catch blocks have been shown to be extremely slow on certain browsers (the iPhone’s version of Safari for example).

Comment by Anonymous — October 3, 2007

Neglecting the try/catch and micro-optimization accusations for a moment, I started with a similar chunk of code copied from Dojo (dojo/src/hostenv_browser.js) and applied the lazy function pattern as well, except that I managed to refactor some of the logic by using an array of functions.

Microsoft.XMLHTTP will always get versions up to 3. Checking for Msxml2.XMLHTTP is a waste of time since it always gets version 3. Msxml2.XMLHTTP.4.0 and 6.0 are not returned by Microsoft.XMLHTTP. 6.0 was released with Vista. page 3

This is a great exercise for the Lazy Function Declaration pattern, if only for its educational value, or because try/catch is expensive.

This sample is pretty green though (in the arboreal sense). It doesn’t take into account status eccentricities of various browsers over various protocols. For example KHTML doesn’t mask the 304 cache hit status (other browsers handle it and change it to a 200). Also in some browsers, under various conditions, you’ll get “undefined” or “0” for OK.

Comment by Kris Kowal — October 3, 2007

[quote] I don’t understand why frameworks must use a try/catch (try/catchs are usually not very fast, and very annoying with Firebug).[/quote]

Disable ActiveX and see what happens.

Comment by Eric Pascarello — October 3, 2007


Considering your argument about disabling ActiveX, I’d still narrow the try/catch block down to the ActiveX control construction.

But you simply don’t need to try/catch anything, if ActiveX is disabled and window.XMLHttpRequest doesn’t exist you can perfectly verify that you got what you need without “trying”.

Comment by Rogier — October 3, 2007

Totally agree with you. Object detection is always the way to go.

My comment is basically why you probably would want to use the around the ActiveX. Talked about the error a long time ago on my blog here:


Comment by Eric Pascarello — October 3, 2007

Am I the only one, who prefers higher level “complexity”? I know that try-catch is slow or that foreach-like syntax is bad for performance, but I prefer to let these things handled by frameworks (either inhouse, or for pet projects prototype.js) – hardware components and browsers are getting faster/better by the day (by the year, sry:)), but code reusability and readibility will not improve by itself.

Comment by deadcabbit — October 4, 2007

@deadcabbit What you say is true, but only if the effect is (near) transparent. In the case of try-catch it isn’t on the iPhone. It literally takes seconds to pass try catch blocks.

Comment by Anonymous — October 4, 2007

As others have already pointed out in the article comments, this code doesn’t work at all, because readyState is only checked once before sending the request (instead of polling or putting it on onreadystatechange event)

Comment by Mourner — October 4, 2007

Leave a comment

You must be logged in to post a comment.