Let's Make a Framework: Ajax

Alex R. Young





tutorials frameworks lmaf ajax

Let's Make a Framework: Ajax

Posted by Alex R. Young on .

tutorials frameworks lmaf ajax

Let's Make a Framework: Ajax

Posted by Alex R. Young on .

Welcome to part 13 of Let's Make a Framework, the ongoing series about
building a JavaScript framework. This part discusses Ajax.

If you haven't been following along, these articles are tagged with
lmaf. The project we're creating is called Turing and is available on GitHub:


All XMLHttpRequest really does is allows browsers to send messages
back to the server. Combined with DOM manipulation, this allows us to update or replace parts of a page. This simple API marked a radical
change in web application development, and rapidly became commonplace.

Requests must adhere to the same origin policy. This means a request
has to call a server at a given domain. This limitation can be
side-stepped by using dynamically inserted script tags, image tags, and


XMLHttpRequest is another technology that one player in the browser war
pioneered, while the others had to catch up. What's interesting about
XMLHttpRequest is Microsoft created the concept behind it -- not Mozilla
or the W3C. Although ActiveX was used, equivalent functionality shipped
with Internet Explorer 5.0 in 1999. It wasn't until 2006 that the W3C
published a working draft for XMLHttpRequest itself.

Request Objects

In this series of tutorials I'm going to focus on XMLHttpRequest as well
as other network-related techniques. Following
Glow's lead, I'll use the namespace turing.net.

Frameworks like jQuery make XMLHttpRequest look incredibly simple, but
there's actually a fair bit going on behind the scenes:

  1. Differences between Microsoft's implementation and W3C have to be
    dealt with
  2. Request headers must be set for the type of data and HTTP methpd
  3. State changes must be handled through callbacks
  4. Browser bugs must be compensated for

Creating a request object looks like this:

// W3C compliant
new XMLHttpRequest();
// Microsoft
new ActiveXObject("Msxml2.XMLHTTP.6.0");
new ActiveXObject("Msxml2.XMLHTTP.3.0");
new ActiveXObject('Msxml2.XMLHTTP');

Internet Explorer has different versions of MSXML -- these are the
preferred versions based on Using the right version of MSXML in

jQuery's implementation looks like this:

xhr: window.XMLHttpRequest && (window.location.protocol !== "file:" || !window.ActiveXObject) ?
  function() {
    return new window.XMLHttpRequest();
  } :
  function() {
    try {
      return new window.ActiveXObject("Microsoft.XMLHTTP");
    } catch(e) {}

This code uses a ternary operator to find a valid transport. It also has
a note about preventing IE7 from using XMLHttpRequest, because it can't
load local files.

More explicitly, finding the right request object looks like this:

function xhr() {
  if (typeof XMLHttpRequest !== 'undefined' && (window.location.protocol !== 'file:' || !window.ActiveXObject)) {
    return new XMLHttpRequest();
  } else {
    try {
      return new ActiveXObject('Msxml2.XMLHTTP.6.0');
    } catch(e) { }
    try {
      return new ActiveXObject('Msxml2.XMLHTTP.3.0');
    } catch(e) { }
    try {
      return new ActiveXObject('Msxml2.XMLHTTP');
    } catch(e) { }
  return false;

Sending Requests

There are three main parts to sending a request:

  1. Set a callback for onreadystatechange
  2. Call open on the request object
  3. Set the request headers
  4. Call send on the object

The onreadystatechange callback can be used to call
user-supplied callbacks for request success and failure. The following
states may trigger this callback:

  • 0: Uninitialized: open has not been called
  • 1: Loading: send has not been called
  • 2: Loaded: send has been called, headers and status are available
  • 3: Interactive: Downloading, responseText holds the partial data
  • 4: Completed: Request finished

The open function is used to initialize the HTTP method,
set the URL, and determine if the request should be asynchronous.
Request headers can be set with request.setRequestHeader(header,
. The post body can be set with

This simple implementation uses the previously defined xhr
function to send requests:

function ajax(url, options) {
  function successfulRequest(request) {
    return (request.status >= 200 && request.status < 300) ||
        request.status == 304 ||
                (request.status == 0 && request.responseText);

  function respondToReadyState(readyState) {
    if (request.readyState == 4 ) {
      if (successfulRequest(request)) {
        if (options.success) {
      } else {
        if (options.failure) {

  function setHeaders() {
    var headers = {
      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'

    for (var name in headers) {
      request.setRequestHeader(name, headers[name]);

  var request = xhr();
  if (typeof options === 'undefined') {
    options = {};

  options.method = options.method ? options.method.toLowerCase() : 'get';
  options.asynchronous = options.asynchronous || true;
  options.postBody = options.postBody || '';

  request.onreadystatechange = respondToReadyState;
  request.open(options.method, url, options.asynchronous);

Popular APIs

jQuery uses methods like get and post. These are shorthands for the
ajax function:

  url: url,
  data: data,
  success: success,
  dataType: dataType

Prototype uses classes -- Ajax.Request is the main one.
Typical usage looks like this:

new Ajax.Request('/your/url', {
  onSuccess: function(response) {
    // Handle the response content...

Glow framework 1.7 is interesting because it fires a custom event when
an event succeeds or fails:

if (response.wasSuccessful) {
  events.fire(request, "load", response);
} else {
  events.fire(request, "error", response);

Putting it Together

Using the examples above, I've built turing.net which
implements get, post, and ajax:

turing.net.get('/example', { success: function(r) { alert(r.responseText); } });

It's on GitHub now:

Next Week

Next week I'll continue expanding on the basics created here, and
demonstrate how to implement cross-domain requests.