The XMLHttpRequest Reuse Dilemma
There is a better solution that this posted here: http://radio.javaranch.com/pascarello/2006/03/31/1143817890773.html. So you can read this just to see the wrong way of doing it and the right way is on that link!
One thing I see popping up over message boards is people want to reuse the XMLHttpRequest Object instead of creating a new instance every single time. Some developers think this will help in memory leaks. I have not tested it in any way to see if it really helps. But I thought that I would show you it is possible to reuse the same object over again and again with Internet Explorer.
For this code I am going to be using a very basic example. I am not going to use OO code so just bear with it. With Firefox you are able to reuse the XMLHttpRequest object without this craziness, but with Internet Explorer 6 you are not able to do that (I have not tested this in IE 7 yet so hopefully someone will comment on the reuse factor!)
The basic reuse example
So with the following two buttons below, I will try to load different xml documents. In Firefox you should have no issues loading each one as long as you wait for the file to load completely before pushing the second button. (You need to Remember I am not doing OO stuff here, hence why you need to wait until you push!) With IE6 you should be able to only load one of the documents and the other one should not load. So click away!
Now the code for this request is below so you can see what it is doing exactly.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Example 1 - Basic Request</title>
<script type="text/javascript">
function getXHR(){
var newReq = null;
if(window.XMLHttpRequest) {
try {
newReq = new XMLHttpRequest();
}
catch(e) {
newReq = false;
}
}
else if(window.ActiveXObject) {
try {
newReq = new ActiveXObject("Msxml2.XMLHTTP");
}
catch(e) {
try {
newReq = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e) {
newReq = false;
}
}
}
return newReq;
}
var req_fail_IE = getXHR();
function loadXHR_fail_IE(url) {
if(req_fail_IE) {
req_fail_IE.onreadystatechange = processReqChange_fail_IE;
req_fail_IE.open("GET", url, true);
req_fail_IE.send("");
}
else{
alert("The XMLHttpRequest Object is not supported");
}
}
function processReqChange_fail_IE() {
if (req_fail_IE.readyState == 4) {
if (req_fail_IE.status == 200 || req_fail_IE.status == 0) {
alert(req_fail_IE.responseText);
}
else {
alert("There was an issue retrieving the data:\n" +
"Reason: " + req_fail_IE.statusText);
}
}
}
</script>
</head>
<body>
<form id="Form1">
<input type="button" name="b1" value="Bad - Test1" onclick="loadXHR_fail_IE('Test1.xml')" />
<input type="button" name="b2" value="Bad - Test2" onclick="loadXHR_fail_IE('Test2.xml')" />
</form>
</body>
</html>
As you can see the example above shows the problems with cross browser differences. So we need to find a solution that solves it. Luckily it is rather easy to get the cross browser solution working.
The abort reuse example
How do we get around this problem with IE? Firefox is smart ought to figure it out! The solution is actually really simple. It involves the abort() method. Seems like everyone forgets the abort method exists. The abort method cancels the request. So if we call the abort() method on our XMLHttpRequest object, we are able to reuse it again with IE. Click the following buttons with IE and you will see that both files load (Remember no OO here so wait till it loads to execute the second click!)
You can see all we needed to do was add a little if else statement in the function on the code listing below.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Example 1 - Basic Request</title>
<script type="text/javascript">
var req = null;
function getXHR(){
var newReq = null;
if(window.XMLHttpRequest) {
try {
newReq = new XMLHttpRequest();
}
catch(e) {
newReq = false;
}
}
else if(window.ActiveXObject) {
try {
newReq = new ActiveXObject("Msxml2.XMLHTTP");
}
catch(e) {
try {
newReq = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e) {
newReq = false;
}
}
}
return newReq;
}
function loadXHR(url) {
if(req==null){
req = getXHR();
}
else if(req){
req.abort();
}
if(req) {
req.onreadystatechange = processReqChange;
req.open("GET", url, true);
req.send("");
}
else{
alert("The XMLHttpRequest Object is not supported");
}
}
function processReqChange() {
if (req.readyState == 4) {
if (req.status == 200 || req.status == 0) {
alert(req.responseText);
}
else {
alert("There was an issue retrieving the data:\n" +
"Reason: " + req.statusText);
}
}
}
</script>
</head>
<body>
<form id="Form1">
<input type="button" name="b3" value="Good - Test1" onclick="loadXHR('Test1.xml')" />
<input type="button" name="b4" value="Good - Test2" onclick="loadXHR('Test2.xml')" />
</form>
</body>
</html>
To implement this type of logic in an OO JavaScript manner would be tricky, ah not really if you coded it well. Hopefully someone out there will run tests to see if this actually helps cut down on memory leaks or actually creates a bigger one. That is a good project for someone!
Eric Pascarello
Coauthor of Ajax In Action
Moderator of HTML/JavaScript at www.JavaRanch.com
Author of: JavaScript: Your Visual Blueprint for Dynamic Web Pages
Those two links are two good places to start.
Eric
The browser already queues up requests since IE can only make 2 at a time since we can only have 2 open connections to a site. Same reason images take a while to load on a page.
So if we just fire requests than it will just queue up until a connection is open. But this does not guarntee a loading order so one can load before the next.
By adding a coded queue you can make sure that the browser maintains order and you can reuse the object.
Now the reason why the XMLHttpRequest is "heavy" as Derek said is the browser's bad garbage collection. Memory leaks are not uncommon with poorly written code so we need to make sure we eliminate every little memory hole.
Eric
If you follow that bold link I posted in the very first line I wrote, it says what the problem was with it and how to fix it. It has already been pointed out to me.
Eric