In depth look at Ajax's XMLHttpRequest object - Part 1 ( Introduction)

The click-and-wait pattern has dominated for years the client/server communication but with the introduction of Ajax things have become different. The interaction of the user with an Ajax-enabled application becomes much more interactive and enjoyable. Gone the days when the user was forced to perform a full page postback to get/update data from/to the server. Now, with Partial Page rendering and asynchronous callbacks, Web Pages have become much more smarter, responsive and faster.

At the heart of Ajax is a JavaScript object called XMLHttpRequest. Simply put, this object allows you to send data to and receive data from to the server in an asynchronous fashion. But hold on a minute, are you saying asynchronous ?

Yes, actually Ajax adds an intermediate layer between the browser and the server, a layer that runs on your computer and request data only when it is needed ( through an Ajax Scheduler ) – Asynchronous Communication . This actually breaks the classical interaction with the Web when the browser request a page from the server and the server responds to this request and sends back a brand new HTML document to be parsed/rendered by the browser – Synchronous Communication. But isn’t Asynchronous communication much more complex and harder to handle? You are right, but with the introduction of many new Ajax frameworks ( like ASP.NET Ajax framework), this complexity is abstracted away from the developer. I didn’t get it, complexity alone doesn’t justify Ajax usefullness, I am not convinced…

OK, OK, here is what happens when a Synchronous Ajax request is made, I refer to it as SJAX request ( not funny!). With Synchronous request the Ajax engine in the browser is locked until the response is sent back to the server. It works well locally ( on Localhost) or on a LAN but connecting to a server that is under heavy load , user experience is sacrificed and the Web application performs badly ( the browser will hit 0 degrees Celsius in no time!). With Asynchronous requests the JavaScript engine is not blocked. Aha! Now I see, Ajax for life!.

The first step in creating an asynchronous request is by Instantiating the XMLHttpRequest Object. Here we go :

XMLHttpRequest Instantiation is Browser-Dependent :
   1: function FactoryXMLHttpRequest()
   2: {
   3:     if(window.XMLHttpRequest) //IE7, FireFox
   4:     {

5: return new XMLHttpRequest();

   6:     }
   7:     else if(window.ActiveXObject)//IE6
   8:     {
   9:         var msxmls = null;
  10:                 
  11:         msxmls = new Array('Microsoft.XMLHTTP','Msxml2.XMLHTTP');
  12:                 
  13:         try
  14:         {
  15:             for(var i = 0; i < msxmls.length; i++)
  16:             {
  17:                 return new ActiveXObject(msxmls[i]);
  18:             }
  19:         }
  20:         catch(e)
  21:         {
  22:         }
  23:     }
  24:      
  25:     throw new Error("Could not instantiate XMLHttpRequest");
  26: }
Code Explanation :

If the browser's window object has an implementation of the XMLHttpRequest class, we instantiate it and return it as an object to send a request to the server.In IE7 the XMLHttpRequest is implemented as a native class but in IE6 it is represented as a " Microsoft.XMLHTTP " or "Msxml2.XMLHTTP " ActiveX object. If the code was not able to instantiate a new XMLHttpRequest I throw an exception... what? throwing an exception when people are trying to catch them, please justify! ok, don't get mad there is a good reason behind it. I actually had the choice to return a null object but for someone diagnostic your code and calling this function from a script file he is expecting an object not a null reference, so the best approach is to throw an exception rather than returning a null object which make the code breaks mysteriously.

 

Ok, you have the object, now what? Well every object presents capabilities and characteristics :

 

XMLHttpRequest class methods (Capabilities):

Method Description
abort() Stops a request that is being Processed.
getAllResponseHeaders()

Returns the complete set of HTTP headers from the HTTP request as a string.

open(method, URL, asyncFlag, username, password)

Opens and prepares an HTTP request identified by the HTTP method and URL. The variable asyncFlag can either be true or false, where true means to make an asynchronous request. The variables username and password are used to access a protected HTTP resource.

send(content)

Executes the HTTP request, where the variable content represents data that is posted if applicable.

setRequestHeader(label, value) Assigns an HTTP header before the HTTP request is made.

 

XMLHttpRequest class Properties (Characteristics):

Property Description
readyState

The XMLHttpRequest exposes an integer property named readyState with possible values of 0 , 1 , 2 , 3 , or 4 . The XMLHttpRequest goes through different states during its lifecycle, and each state is associated with one of these five possible values.

status This property contains the HTTP status code of the server response.
statusText This property contains the HTTP status text of the server response
responseText This property contains the server response in text format.
responseXML

This property contains the server response in XML format (an XML Document to be exact). This property is set only when the Content-Type response header is set to the value text/xml.

 

XMLHttpRequest class Events (Characteristics):

Event Description
onreadystatechange

You must assign a reference to a JavaScript function to this property. The
XMLHttpRequest invokes this JavaScript function every time its state changes, which is every
time its readyState property changes value. Used only for Asynchronous calls, when the asynchFlag in the open method is set to true.

 

O.K., enough theory, show me some action please!

 

Sending an Asynchronous call to the server :

   1: function GetIt(url) 
   2: {
   3:     if(xmlhttp) 
   4:     {
   5:         xmlhttp.open('GET', url, true);
   6:         xmlhttp.onreadystatechange = AsyncUpdateEvent;
   7:         xmlhttp.send(null);
   8:     }
   9: }
Code Explanation:

The first action you need is to open a connection to the server, therefor you use the open() method of the XmlHttpRequest Object. Before that you need to check if an XMLHttpRequest object is instantiated ( xmlhttp is actually a global variable of the JavaScript block defined as follows :

var xmlhttp = FactoryXMLHttpRequest();

The Open method takes 4 parameters, the first one is the HTTP verb ( Get or POST) the second… wait wait wait, did you say HTTP verb? What the hack is that?

Ok, HTTP stands for HyperText transfer protocol is the protocol used to communicate over the World Wide Web. It is a two way conversation between Browser and server.The Client sends an Http request to the server and server sends back the Http response object ( that contains the object type known as MIME type, length, status code and other informations).

Every HTTP message has a method, this method tells the server what to do. For a Post method we are sending client data to a gateway application for a Get we are sending named resource from the server to the client. The Get method is called a safe method seeing that it only retreive resources from the server, the Post method wich is not safe post back form data to the server for manipulation.

xmlHttp.open('Get', url, true);

this line of code opens an HTTP Get request with a specified resource ( URL) to the server asynchronously.

xmlhttp.onreadystatechange = AsyncUpdateEvent;

This line of code handles the onreadystatechange event of the XMLHttpRequest class by assigning a reference to a function ( we will cover this function later). The onreadystatechange fires every time the readystate property changes ( span from 0 to 4 ).

xmlhttp.send(null);

We send the request by invoking the send() method of the XMLHttpRequest object that takes null content.

 

CallBack function:

   1: function AsyncUpdateEvent() 
   2: {
   3:     switch(xmlhttp.readyState) 
   4:     {
   5:         case 0:
   6:         document.getElementById('status').innerText = "uninitialized";
   7:         break;
   8:         case 1:
   9:         document.getElementById('status').innerText = "loading";
  10:         break;
  11:         case 2:
  12:         document.getElementById('status').innerText = "loaded";
  13:         break;
  14:         case 3:
  15:         document.getElementById('status').innerText = "interactive";
  16:         break;
  17:         case 4:
  18:         document.getElementById('status').innerText = "complete";
  19:         document.getElementById('result').innerText = xmlhttp.responseText;
  20:         break;
  21:     }
  22: }
Code Explanation :

The readState property indicates the stages of the HTTP Request :

   0: The XMLHttpRequest instance is in an inconsistent state, and the result data should not be referencing.
   1: A request is in progress, and the result data should not be retrieved.
   2: The request has downloaded the result data and is preparing it for reference.
   3: The script can interact with the XMLHttpRequest instance even though the data is not  completely loaded.
   4: The request and result data are completely downloaded and loaded as an object model.

Executing the asynchronous Ajax application results in a call being made, and the browser is not locked. You can click a button, open a new browser, and surf to another website. this is the goodness of Asynchronous callbacks.

Finally we retreive the response results and assign it to the innerText property of the result span tag. ( Label control )

 

What is not optimal with an Asynchronous callback is that you don't have an indicator that point that a request is being processed. So there should be some indicator that something is happening. Another problem is that some Browsers will cache the results of the XMlhttpRequest causing an unpredictable behavior.

 

Complete Code Listing :

 

Default.aspx :

   1: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="HelloWorld._Default" %>
   2:  
   3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   4:  
   5: <html xmlns="http://www.w3.org/1999/xhtml" >
   6: <head runat="server">
   7:     <title>Untitled Page</title>
   8:     <script type="text/javascript" language="javascript">
   9:         
  10:         var xmlHttp = FactoryXMLHttpRequest();
  11:         
  12:         
  13:         function FactoryXMLHttpRequest()
  14:         {
  15:             if(window.XMLHttpRequest)
  16:             {
  17:                 return new XMLHttpRequest();
  18:             }
  19:             else if(window.ActiveXObject)
  20:             {
  21:                 var msxmls = new Array('Microsoft.XMLHTTP','Msxml2.XMLHTTP');
  22:                 
  23:                 try
  24:                 {
  25:                     for(var i = 0; i < msxmls.length; i++)
  26:                     {
  27:                         return new ActiveXObject(msxmls[i]);
  28:                     }
  29:                 }
  30:                 catch(e)
  31:                 {
  32:                 }
  33:             }
  34:         }    
  35:         
  36:         function GetIt(url)
  37:         {
  38:             if(xmlHttp)
  39:             {
  40:                 xmlHttp.open('Get',url,true);
  41:                 xmlHttp.onreadystatechange = GetData;
  42:                 xmlHttp.send(null);
  43:                 
  44:             }
  45:         }
  46:         
  47:         function GetData()
  48:         {
  49:             switch(xmlHttp.readyState) 
  50:             {
  51:                 case 0:
  52:                 document.getElementById('status').innerText = "uninitialized";
  53:                 break;
  54:                 case 1:
  55:                 document.getElementById('status').innerText = "loading";
  56:                 break;
  57:                 case 2:
  58:                 document.getElementById('status').innerText = "loaded";
  59:                 break;
  60:                 case 3:
  61:                 document.getElementById('status').innerText = "interactive";
  62:                 break;
  63:                 case 4:
  64:                 document.getElementById('status').innerText = "complete";
  65:                 document.getElementById('result').innerText = xmlHttp.responseText;
  66:                 break;
  67:             }
  68:  
  69:         }
  70:     
  71:     
  72:     </script>
  73: </head>
  74: <body>
  75:     <form id="form1" runat="server">
  76:     <div>
  77:     
  78:         <asp:Button OnClientClick="GetIt('AsynchronousPage.aspx'); return false;" 
  79:             ID="Button1" runat="server" Text="Asynchronous Call" /><br />
  80:         
  81:         <asp:Label ID="status" runat="server" Text=""></asp:Label><br />
  82:         <asp:Label ID="result" runat="server" Text=""></asp:Label>
  83:         
  84:     </div>
  85:     </form>
  86: </body>
  87: </html>

 

Asynchronous.aspx Code behind :

   1: using System;
   2: using System.Collections;
   3: using System.Configuration;
   4: using System.Data;
   5: using System.Linq;
   6: using System.Web;
   7: using System.Web.Security;
   8: using System.Web.UI;
   9: using System.Web.UI.HtmlControls;
  10: using System.Web.UI.WebControls;
  11: using System.Web.UI.WebControls.WebParts;
  12: using System.Xml.Linq;
  13:  
  14: namespace HelloWorld
  15: {
  16:     public partial class AsynchronousPage : System.Web.UI.Page
  17:     {
  18:         protected void Page_Load(object sender, EventArgs e)
  19:         {
  20:             System.Threading.Thread.Sleep(10000);
  21:             Response.Write("Hello Ajax");
  22:             Response.Flush();
  23:             Response.End();
  24:         }
  25:     }
  26: }

The current thread on the server is set to sleep for 10 seconds just to see visually the different stages of the XMLHttpRequest object Request.

 

I hope you have enjoyed reading this tutorial as much as I did writing it.

Download Solution - XmlHttpRequest.zip

Published Sunday, January 27, 2008 1:15 PM by Joseph Ghassan
Filed under:

Comments

# Fashion &raquo; In depth look at Ajax&#8217;s XMLHttpRequest object - Part 1 ( Introduction)

Pingback from  Fashion &raquo; In depth look at Ajax&#8217;s XMLHttpRequest object - Part 1 ( Introduction)

# re: In depth look at Ajax's XMLHttpRequest object - Part 1 ( Introduction)

Sunday, January 27, 2008 12:33 PM by rrobbins

An introduction to the XMLHttpRequest object should mention the cross domain request restriction which can be a problem in some senarios. I really prefer JSON with a callback function now.

# re: In depth look at Ajax's XMLHttpRequest object - Part 1 ( Introduction)

Sunday, January 27, 2008 1:12 PM by Joseph Ghassan

Hi Robbins,

Yes, you have a point.You can always enable security to allow cross-domain calls ( in IE7 and FF) but messing with security setting is a problem too. Rest assured that I will be covering these issues and JSON in the upcoming articles.

# t`1 83 connection status

Saturday, May 10, 2008 10:16 PM by t`1 83 connection status

Pingback from  t`1 83 connection status

# re: In depth look at Ajax's XMLHttpRequest object - Part 1 ( Introduction)

Thursday, June 19, 2008 4:07 AM by Bharat

Ultimate Ariticle. Thank you very much.

Bharat Gambhir

# re: In depth look at Ajax's XMLHttpRequest object - Part 1 ( Introduction)

Thursday, June 19, 2008 5:20 AM by Bharat

Very good Article...

# re: In depth look at Ajax's XMLHttpRequest object - Part 1 ( Introduction)

Thursday, June 04, 2009 10:37 AM by Jayant R

I have spent two days searching for a good ajax article. I am overwhelmed to find such a great article.

Hats Off !!!

Leave a Comment

(required) 
(required) 
(optional)
(required)