Digging deeper into HTTP ready states

Ajax tutorial | PREV | NEXT

You should remember from the last article that the XMLHttpRequest object has a property called readyState. This property ensures that a server has completed a request and typically, a callback function uses the data from the server to update a Web form or page. Listing 1 shows a simple example of this.

Listing 1. Deal with a server's response in a callback function
 function updatePage() {
   if (request.readyState == 4) {
     if (request.status == 200) {
       var response = request.responseText.split("|");
       document.getElementById("order").value = response[0];
       document.getElementById("address").innerHTML =
         response[1].replace(/\n/g, "<br />");
     } else
       alert("status is " + request.status);

This is definitely the most common (and most simple) usage of ready states. As you might guess from the number "4," though, there are several other ready states (you also saw this list in the last article -- see Resources):

If you want to go beyond the basics of Ajax programming, you need to know not only these states, but when they occur and how you can use them. First and foremost, you need to learn at what state of a request you encounter each ready state. Unfortunately, this is fairly non-intuitive and also involves a few special cases.

Ready states in hiding

The first ready state, signified by the readyState property 0 (readyState == 0), represents an uninitialized request. As soon as you call open() on your request object, this property is set to 1. Because you almost always call open() as soon as you initialize your request, it's rare to see readyState == 0. Furthermore, the uninitialized ready state is pretty useless in practical applications.

Still, in the interest of being complete, check out Listing 2 which shows how to get the ready state when it's set to 0.

Listing 2. Get a 0 ready state
   function getSalesData() {
     // Create a request object
     alert("Ready state is: " + request.readyState);

     // Setup (initialize) the request
     var url = "/boards/servlet/UpdateBoardSales";
     request.open("GET", url, true);
     request.onreadystatechange = updatePage;

In this simple example, getSalesData() is the function that your Web page calls to start a request (like when a button is clicked). Note that you've got to check the ready state before open() is called. Figure 1 shows the result of running this application.

Figure 1. A ready state of 0
A ready state of 0
Obviously, this doesn't do you much good; there are very few times when you'll need to make sure that open() hasn't been called. The only use for this ready state in almost-real-world Ajax programming is if you make multiple requests using the same XMLHttpRequest object across multiple functions. In that (rather unusual) situation, you might want to ensure that a request object is in an uninitialized state (readyState == 0) before making a new requests. This essentially ensures that another function isn't using the object at the same time.
When 0 is equal to 4
In the use case where multiple JavaScript functions use the same request object, checking for a ready state of 0 to ensure that the request object isn't in use can still turn out to be problematic. Since readyState == 4 indicates a completed request, you'll often find request objects that are not being used with their ready state still set at 4 -- the data from the server was used, but nothing has occurred since then to reset the ready state. There is a function that resets a request object called abort(), but it's not really intended for this use. If you have to use multiple functions, it might be better to create and use a request object for each function rather than to share the object across multiple functions.

Viewing an in-progress request's ready state

Aside from the 0 ready state, your request object should go through each of the other ready states in a typical request and response, and finally end up with a ready state of 4. That's when the if (request.readyState == 4) line of code you see in most callback functions comes in; it ensures the server is done and it's safe to update a Web page or take action based on data from the server.

It is a trivial task to actually see this process as it takes place. Instead of only running code in your callback if the ready state is 4, just output the ready state every time that your callback is called. For an example of code that does this, check out Listing 3.

Listing 3. Check the ready state
   function updatePage() {
     // Output the current ready state
     alert("updatePage() called with ready state of " + request.readyState);

If you're not sure how to get this running, you'll need to create a function to call from your Web page and have it send a request to a server-side component (just such a function was shown in Listing 2 and throughout the examples in both the first and second articles in this series). Make sure that when you set up your request, you set the callback function to updatePage(); to do this, set the onreadystatechange property of your request object to updatePage().

This code is a great illustration of exactly what onreadystatechange means -- every time the request's ready state changes, updatePage() is called and you see an alert. Figure 2 shows a sample of this function being called, in this case with a ready state of 1.

Figure 2. A ready state of 1
A ready state of 1

Try this code yourself. Put it into your Web page and then activate your event handler (click a button, tab out of a field, or use whatever method you set up to trigger a request). Your callback function will run several times -- each time the ready state of the request changes -- and you'll see an alert for each ready state. This is the best way to follow a request through each of its stages.

Browser inconsistencies

Once you've a basic understanding of this process, try to access your Web page from several different browsers. You should notice some inconsistencies in how these ready states are handled. For example, in Firefox 1.5, you see the following ready states:

This shouldn't be a surprise since each stage of a request is represented here. However, if you access the same application using Safari, you should see -- or rather, not see -- something interesting. Here are the states you see on Safari 2.0.1:

Safari actually leaves out the first ready state and there's no sensible explanation as to why; it's simply the way Safari works. It also illustrates an important point: While it's a good idea to ensure the ready state of a request is 4 before using data from the server, writing code that depends on each interim ready state is a sure way to get different results on different browsers.

For example, when using Opera 8.5, things are even worse with displayed ready states:

Last but not least, Internet Explorer responds with the following states:

If you have trouble with a request, this is the very first place to look for problems. Add an alert to show you the request's ready state so you can ensure that things are operating normally. Better yet, test on both Internet Explorer and Firefox -- you'll get all four ready states and be able to check each stage of the request.

Next I look at the response side.




Home | Ajax tutorials | JavaScript Editor JavaScript EditorGet Advanced
JavaScript and Ajax Editor,
Validator and Debugger!

1st JavaScript Editor.