Friday, March 18, 2005

XMLHTTP and readyState

Given how the world of web design is currently enamored with Ajax — a.k.a. Asynchronous JavaScript + XML, a.k.a. remote scripting with XML messages, a.k.a. a technology that back in 2000 was considered way too rawk star and subversive until Google started playing with it recently — I thought I'd unearth this oldie-but-goodie from 2002. Enjoy.

Microsoft's XMLHTTP object is an ActiveX component that lets you perform HTTP requests. The object has four different states that it cycles through when performing a request. One of those states is called "interactive" and is decribed as such (from the MSDN documentation):

(3) INTERACTIVE
Some data has been received. You can call responseBody and responseText to get the current partial results.

...meaning that at that point you should be able to examine the contents of the response so far. Let's try this, shall we?

var xmlHTTP = new ActiveXObject("Microsoft.XMLHTTP");
xmlHTTP.onreadystatechange = handleStateChange;

function handleStateChange()
{        
    if (xmlHTTP.readyState == 3)
    {
        alert(xmlHTTP.responseText);
    }
}

xmlHTTP.open("POST","/some/uri",true);
xmlHTTP.send();

Execution of this code produces an error in the handler:

The data necessary to complete this operation is not yet available.

...which troubles me greatly. Waiting until readyState is 4 (complete) works perfectly, but there's an added complication: the URI /some/uri establishes a persistent connection, which means that unless the connection is terminated by the script or the server, readyState will always be 3 (interactive). According to the docs, I should be able grab the incomplete response from the server at this time, but apparently not. Possible reasons:

  • the MSDN documentation is a big fat lie incorrect
  • the XMLHTTP object has a huge buffer to fill before it will make the response available
  • the object needs to see some sort of delimiter, like a null byte, as a signal to make the response text available
  • I'm horribly misunderstanding the whole thing

UPDATE 3/4/2004: many. many people have written me to ask if I have found a workaround since I first posted this. I'm sorry to say that I have not.

11 Comments:

At 12:42 PM, Anonymous Anonymous said...

the documentation for XMLHTTP clearly states that, in the interactive state, the responseBody and responseText properties will return an error because status and response headers are not fully available. Do do async reads, you need to use the DOMDocument object. You can handle the ondataavailable event to tell when you have new content available to read.

 
At 9:01 AM, Blogger Sam-I-Am said...

Go on... Mr/Ms anonymous, this very problem is one of my open bugs and you seem to be in possesion of the fix. Can you spell it out a bit? An example? Do you mean use the DOMDocument object vs. the XmlHttpRequest object?

Are you also saying that if I simply ignore all but the complete ready response I don't need to worry about it?

 
At 12:38 PM, Blogger Tom Trenka said...

If you are using MS XMLHTTP from script, then the only time you will be able to access responseXml or responseText is when readyState, in fact, == 4. It's not an error in the documentation either...

Here's the basic deal. The MS XmlHttp object was written to be usable as a straight up COM+ object, not just from script. This means that it's available to C++ and VB programs (or anything else capable of consuming COM+ objects).

This, in itself, isn't such a surprise or a big deal.

However, the MS version of the object comes with two additional properties not mimicked by Moz, Safari (or now Opera, apparently): .responseStream and .responseBody. The first returns an IStream, the second an array of bytes. Neither are accessible via script...and both are accessible at any time during the loading process...i.e. when responseState == 2 or 3.

So...the bottom line is that the MSDN documentation is actually correct, it's just that since JS doesn't support byte arrays or streams, you can't get at it.

In other words, there is no solution. Sorry :)

 
At 8:36 AM, Blogger Lost in the World said...

After much testing, I've proved that although the XMLHTTP returns a responseStream, the data is only available (even in IStream format) once the XMLHTTP.readyState = 4, which is when the data has been fully populated. (as per tom trenka's comment)

This almost makes the IStream interface from the XMLHTTP object pointless.

As I was ultimately trying to load a SAXXMLReader data with a stream from a URL, I did a bit of a work around and managed to use the SAXXMLReader.parseURL. This loads a xml stream far better. (once it's large buffer has been filled)

 
At 7:48 PM, Blogger 122272 said...

Nice blog you have here! If you get a chance you may want to visit this natural penis enlargement reviews site, it's a very nice site.

 
At 11:04 AM, Blogger Unknown said...

Increase your Adsense Earnings

I noticed you have adsense ads on your page, Would you like to increase your earnings from them, Free and Legitimate way to make your clicks increase.
Come see my Blogger blog and it will tell you more.

 
At 5:51 AM, Blogger HiiFii Webservices said...

I liked you Blog so much,so i also wanted to show you some good resourses on the net.
Learn to earn 90000$/Month
For which you may also see my Personal Website
Here.
and for a Personal Education Career Tools
free Study Database.
This site is for seeing the
Hifi Electronics.
And this is for
World Class Gadgets

 
At 8:35 PM, Blogger WhiteOak said...

Can someone email me with info on small penis and how to sign up for the newsletter?

Ron
small penis

 
At 3:18 AM, Blogger cicerchia said...

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

if((window.ActiveXObject)){
if(x.responseBody != null ){
el = document.getElementById("inside");
el.innerHTML ="some thing";
}else{
el = document.getElementById("inside");
el.innerHTML = 'some thing';
}
}else{
if(x.responseText.length != 0){
el = document.getElementById("inside");
el.innerHTML ="some thing";

}else{
el = document.getElementById("inside");
el.innerHTML = 'some thing';
}

}
}
}


This is a good Work Around.

Do you Know Cicerchia????

Bye Bye from Rome

 
At 1:55 PM, Blogger bloke said...

This comment has been removed by a blog administrator.

 
At 1:57 PM, Blogger bloke said...

how about using a javascript timeout that continues until readyState = 4, this way the document can continue to load while the javascript runs the async function, when readyState = 4, then exit the async and carry on with normal processing.

 

Post a Comment

<< Home