i am dustin diaz

a JavaScriptr...

boosh.

don't worry about it.

Making Ajax Elegantly Fast

Sometime ago I was messing around with various techniques for ways that we can optimize asynchronous calls to the server via XMLHttpRequest (and the ActiveX equivalent of XMLHTTP). I wrote about one of those techniques known as branching in an article for Digital Web Magazine called Seven JavaScript Techniques You Should Be Using Today back in April, however, there was a flaw in the function that when one request is made before another one is finished, you would run into an error since it is using the same reference to the instance object for the request. That's cool in theory, but bad in practice. The benefit you get with that is that you never create more than one XMLHttpRequest object for all your requests. This is fine for light weight use, and when you know for sure that you won't be making frequent requests simultaneously. But when does that ever happen? Really. Here's what that code looked like:

Outdated asyncRequest function

var asyncRequest = function() {

    function handleReadyState(o, callback) {

        var poll = window.setInterval(function() {

            if(o && o.readyState == 4) {

                window.clearInterval(poll);

                if ( callback ){

                    callback(o);

                }

            }

        },

        50);

    }

    var http;

    try {

        http = new XMLHttpRequest;

    }

    catch(e) {

        var msxml = [

            'MSXML2.XMLHTTP.3.0', 

            'MSXML2.XMLHTTP', 

            'Microsoft.XMLHTTP'

        ];

        for ( var i=0, len = msxml.length; i < len; ++i ) {

            try {

                http = new ActiveXObject(msxml[i]);

                break;

            }

            catch(e) {}

        }

    }

    return function(method, uri, callback, postData) {

        http.open(method, uri, true);

        handleReadyState(http, callback);

        http.send(postData || null);

        return http;

    };

}();
Note that the function still branches within the body of the closure, and that branch happens only once. The main issue here is that we need another function that essentially branches the way get the XMLHttpRequest object, but without being run multiple times. In other words, this would be bad:

bad example for XMLHttpRequest

function getXHR() {

  var http;

  try {

    http = new XMLHttpRequest;

  } catch (ex) {

    var msxml = [

      'MSXML2.XMLHTTP.3.0', 

      'MSXML2.XMLHTTP', 

      'Microsoft.XMLHTTP'

    ];

    for (var i=0, len = msxml.length; i < len; ++i) {

      try {

        http = new ActiveXObject(msxml[i]);

        break;

      }

      catch(e) {}

    }

  }

}
The reason this is slow is because every request for a new XMLHttpRequest object we have to run through the same logic upon each call to this function. Instead we can use what Peter Michaux coined as the Lazy Function Definition Pattern, and apply that technique here. Our optimized (and final) code would then look like this:

Optmized Speedy Ajax Code

var asyncRequest = function() {

  function handleReadyState(o, callback) {

    if (o && o.readyState == 4 && o.status == 200) {

      if (callback) {

        callback(o);

      }

    }

  }

  var getXHR = function() {

    var http;

    try {

      http = new XMLHttpRequest;

        getXHR = function() {

          return new XMLHttpRequest;

        };

    }

    catch(e) {

      var msxml = [

        'MSXML2.XMLHTTP.3.0', 

        'MSXML2.XMLHTTP', 

        'Microsoft.XMLHTTP'

      ];

      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();

    http.open(method, uri, true);

    handleReadyState(http, callback);

    http.send(postData || null);

    return http;

  };

}();
Take closer look at how the getXHR function is redeclared within main declaration to simply return the appropriate object back to the client when requested. And that folks, is Ajax served elegantly fast! Feel free to try it yourself :)

asyncRequest in use

asyncRequest('GET', 'foo.php', function(o) {

  console.log(o.responseText);
});

this is who i am

Hi, my name is Dustin Diaz and I'm an Engineer @ObviousCorp. Previously @Twitter, @Google, and @Yahoo, author of Strobist® Info co-author of JavaScript Design Patterns, co-creator of the Ender JavaScript Framework, a Photographer, and an amateur Mixologist. This is my website. Welcome!

On this site I write about JavaScript. You can also follow along with my open-source work on Github.

This site is optimized and works best in Microsoft Internet Explorer 6.