3/30/2006

Reusing XMLHttpRequest Object in IE

I came across an article posted by Eric (Coauthor of Ajax In Action) which talks about reusing XMLHttpRequest object. I read many blogs and message boards where similar kind of problem was faced by many users. But frankly speaking I never faced this problem before, except in the example given by Eric in his blog. That made me think why I am able to reuse the same XMLHttpRequest object while others not. So, I decided to write this short article on reusing XMLHttpRequest object in IE.

In the current project I am doing, I implemented AJAX technique and using one instance (yes, you heard it right, only one instance) of XMLHttpRequest object without abort calls and I use IE 6, XP SP2. There is one little trick that you have to use to reuse one instance. I'll take the same example developed by the author in the blog Reusing XMLHtpRequest - dilema and show you how to reuse XMLHttpRequest object.

The code developed in the article uses the javascript statements

req_fail_IE.onreadystatechange = processReqChange_fail_IE;
req_fail_IE.open("GET", url, true);
req_fail_IE.send("");

where it assigns the callback handler to the XMLHttpRequest, open the request and send the request which actually transmits the request.

Instead of this piece of code, just try using the following code and it will do the trick. Believe me and it's worth trying.

req_fail_IE.open("GET", url, true);
req_fail_IE.onreadystatechange = processReqChange_fail_IE; //changed the position of callback handler
req_fail_IE.send("");


I worked on two examples. One that is originally created by Eric,
http://www.geocities.com/keelypavan/Non_Working.html .
and the code I changed (just changed whatever I mentioned above and nothing else, that's why you still see button names as "bad-test1" and "bad-test2", but don't care, both buttons still work even if they are named "bad"). http://www.geocities.com/keelypavan/working.html .
Note: Please bear with those Yahoo geocities ads and if you have pop-up blocker, you may get Javascript errors and these errors are from geocities ads code, please ignore them.

One more important point that I observed is, the request is getting fired even in the first example for the second button, which is not showing up any alert, but the callback handler is not getting called. So, it has to do with assigning callback handler to the XMLHttpRequest's onreadystatechange.

If it doesn't work, please let me know, because I only tested in IE 6, Mozilla Firefox 1.0.7 and no other versions.

Have a great reuse of XMLHttpRequest object and stop memory leaks ( update: I haven't demonstarted this piece).

Update on April 2nd, '06:
I recently got an email from Michael Mahemoff (Author of Ajax Design Patterns and maintaining the site www.ajaxpatterns.org ) about not using abort. His question in his own words:

Michael Mahemoff: What's actually the advantage of not calling abort()? If the call is stuck in state 2 or 3 waiting for a response, wouldn't you want to call abort() anyway?

Pavan Keely:
No, I wouldn’t want to. Because browser is intelligent enough to see whether to proceed with the request furthur or not when I issue one more call on the same XHR object. If one request is being processed on one instance of XHR object and if the application issues one more call on the same XHR, browser will abort the first request and proceeds with the second request. This is not just theoritical analysis but I did few testings too in IE6 which favor my analysis.

For demonstration purposes, I created one example which creates a XHR object when loading and issues 5 requests immediately one after the other in a loop upon a click of "Get Data" button. If you have any TCP probe tools like HTTPWatch or anything like that, please see the requests being fired from the browser. Except for the last call, all previous 4 calls will be "abort"ed. ( There is a basic free version of HTTPwatch available if you don't have one.).

link to the example: http://www.geocities.com/keelypavan/Request_abort_test.html

Probably, this is one of the best practices to call open before setting onreadystatechange and may be calling abort if the request is in process.

23 comments:

Anonymous said...

It is very informative and is written in a comprehensible manner.

Pavan Keely said...

Thomas,

I am not sure whether you would be able to see any memory leak probems with two XMLHttpRequest objects. Imagine the situation where you have to use 40 to 50 requests to the server from a single page. In the current project, I implemented user autofill functionality and in one of the pages it has nearly 40 user fields. That's what my intention in writing that statement.

Pavan Keely

Anonymous said...

Hey as usual u have explained it really well!!Great Stuff!!
Am Impressed!!

Anonymous said...

Isn't there a race condition between open() and setting the handler?

Pavan Keely said...

First two examples developed are just for demonstration purposes taken from Eric's post to show how to reuse the object without abort calls. If you are talking abt the my update on 2nd April, that's purely for demonstration purpose. Please let me know where you think we find problems in the real case situation. We'll analyze the situation and try to find an alternate for this.

Anonymous said...

I believe there is no race condition because the request is not sent over the wire until send() is called.

Anonymous said...

What I do to avoid IE's bug is pass a Timestamp everytime as a parameter to the URL

Pavan Keely said...

Ruturaj,

There are other alternatives for avoiding "GET" cache. You can specify Cache-Control headers on the server side and control how cache is handled. or you can specify if-modified-since HTTP header using XHR and set that date to some past date, so that browser will always get the "GET" request. For more information, read XMLHttpRequest topic in wikipedia.

Anonymous said...

Hi,
We have a strange problem with XHR (IE6.0).
If we abort a request after it times out, we notice in HTTP
tracker(Fiddler), that one of the channels dies (i.e not usable
anymore), and hence after two aborts, we are left with no more AJAX
connections, and the only solution is to close the browser.
Has anyone encountered such a problem before?
I understand that IE allows only 2 parallel AJAX requests at a time,
but am not sure aborting one of them actually frees up the resources as
it is supposed to.
Moreover, if the window is closed before the request comes back, the
same thing happens. I had to shut down all instances of IE to solve
it!!
That makes me wonder if the abort() functions correctly ?!!

Thanks,
Sri

Anonymous said...

Phock! That positional switch actually works. Does not make sense why it should work.

Great job in finding this out! Thanks!

Anonymous said...

Thanks Pavan.

Anonymous said...

This article really help me save a lot of time! Thanks a lot!

Armando MorĂ¡n said...

XmlHttpRequest is evil, I can't get it to clean when I'm reloading the page.

Anonymous said...

Thanks for the tip. Reusing the XHR object in IE plugs the memory leak in my Ajax app.

BTW, it also works in IE 7 and in FF 2.0 (of course its not needed in FF, but its nice that the code is portable).

CK

Anonymous said...

I'm having trouble still. I set an alert to fire whenever my ready state changes in my callback handler. When I reload the page, the onLoad event fires and I see the ready state changes and I get a response from the server. If I click on any other buttons afterwards, I get an alert saying the request was sent but I get no response from the callback function.

XP SP2 IE 7

function sendRequest(url){
url += "&dummy=" + new Date().getTime();
request.open("GET", url, true);
request.onreadystatechange = updatePage;
request.send(null);
alert(url+" -after");
}

function updatePage(){
alert(request.readyState);
if (request.readyState == 4){
alert(request.status);
if(request.status == 200){
var XMLdoc = request.responseXML;
alert(request.responseText);
}
}
}

Here's the onload function and one of my doodads that doesn't work:

function onPageLoad()
{
var url="contactviewer.php?fieldtype=onLoad";
alert(url);
sendRequest(url);
}

function sortFields(fieldName) {
var url="contactviewer.php?fieldtype=button&fieldName="+escape(fieldName);
alert(url);
sendRequest(url);
}

Anonymous said...

This does allow for XHR object reuse, but IE has a nasty habit of caching the request and not actually rerunning it.

To force it to run send request each time you have to tell the browser it must not cache the page using the following:

<!--HTTP 1.0-->
<META Http-Equiv="Cache-Control" Content="no-cache">
<!--HTTP 1.1-->
<META Http-Equiv="Pragma" Content="no-cache">
<!--prevent proxy cache-->
<META Http-Equiv="Expires" Content="0">

Anonymous said...

ch1c0 s4b10: take a look at the onunload event. Fixed it for me!

Dandy said...

Thanks man.....

brian katz said...

Ya thank you SO MUCH. Can't believe switching the order of those two lines fixed what was driving me crazy for 3 hours.

Unknown said...

Thanks a lot! I'm almost surprised to understand so easily these kind of stuff, so I guess it's just beacause of you.

Well, as a newbie I am, I suppose I should ask you about how to get all the XHR objects that are waiting for a response from the server within that html page but, hey!, I better keep looking for the answer on the Internet.

Thanks again.

Unknown said...

You are absolutely fantastic. I spend more than 5 hours searching for this topic, none of one solved my problem with IE reuse of XMLHttpRequest object. Your few lines safe my life.

Kenny said...

Why waste your time on this? Let the garbage collector have something to do. Use your brain cells for something more important.

Dudette said...

Much, much obliged for your solution to my problem, which I'd been struggling with for a week. I'm dealing with having to support a device that has IE6 embedded in it, so all the responses of "why are you supporting IE6? Tell them to upgrade" on other sites was driving me nuts. You wrote this 6 years ago, and I hope you've gotten at least 6 years of good karma from it. Peace.