Drakware

Aug 24 2006 02:33Multiple XMLHTTPRequest Objects Redux

My old article on this subject provided code that worked, but wasn't terribly efficient and did a few unnecessary things. I can't let that just sit there, so here's a better way!

For those new to AJAX/Web 2.0/[Buzzword here], one of the main features is the use of an XMLHTTPRequest object to fetch data in the background without actually changing pages. Most examples show you how to do this, but they don't address what happens when you make multiple simultaneous requests. If you're using a global request object, subsequent requests will overwrite previous ones and you'll never receive a response. That's probably not what you want to happen.

My first solution used a global array of objects, adding them when created and then deleting them once used. This worked, but it required some kludges and it didn't re-use xmlhttp objects. What's the better solution?

var xmlreqs = new Array(); function CXMLReq(freed) { this.freed = freed; this.xmlhttp = false; if (window.XMLHttpRequest) { this.xmlhttp = new XMLHttpRequest(); } else if (window.ActiveXObject) { this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } } function xmlreqGET(url) { var pos = -1; for (var i=0; i<xmlreqs.length; i++) { if (xmlreqs[i].freed == 1) { pos = i; break; } } if (pos == -1) { pos = xmlreqs.length; xmlreqs[pos] = new CXMLReq(1); } if (xmlreqs[pos].xmlhttp) { xmlreqs[pos].freed = 0; xmlreqs[pos].xmlhttp.open("GET",url,true); xmlreqs[pos].xmlhttp.onreadystatechange = function() { if (typeof(xmlhttpChange) != 'undefined') { xmlhttpChange(pos); } } if (window.XMLHttpRequest) { xmlreqs[pos].xmlhttp.send(null); } else if (window.ActiveXObject) { xmlreqs[pos].xmlhttp.send(); } } } function xmlreqPOST(url,data) { var pos = -1; for (var i=0; i<xmlreqs.length; i++) { if (xmlreqs[i].freed == 1) { pos = i; break; } } if (pos == -1) { pos = xmlreqs.length; xmlreqs[pos] = new CXMLReq(1); } if (xmlreqs[pos].xmlhttp) { xmlreqs[pos].freed = 0; xmlreqs[pos].xmlhttp.open("POST",url,true); xmlreqs[pos].xmlhttp.onreadystatechange = function() { if (typeof(xmlhttpChange) != 'undefined') { xmlhttpChange(pos); } } xmlreqs[pos].xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xmlreqs[pos].xmlhttp.send(data); } } function xmlhttpChange(pos) { if (typeof(xmlreqs[pos]) != 'undefined' && xmlreqs[pos].freed == 0 && xmlreqs[pos].xmlhttp.readyState == 4) { if (xmlreqs[pos].xmlhttp.status == 200 || xmlreqs[pos].xmlhttp.status == 304) { handle_response(xmlreqs[pos].xmlhttp.responseXML); } else { handle_error(); } xmlreqs[pos].freed = 1; } }

What does all of that do? Well, it's still the same basic idea of the first method - keep all of our xmlhttp objects in a global array. This time I've expanded on the use of a class to hold the object - it now holds the object and keeps track of whether or not that object is free to re-use. The xmlhttp object is also created when the class is instantiated, which saves us quite a bit of code inside the xmlreqGET/POST functions.

When either xmlreq function is called, it searches the array for a free object and sets pos equal to that object's position (or to the end of the array if no free objects are available). This part saves on resources, as we're not creating a new request object every time we need to use it. Unless you're making a huge amount of requests, you'll probably only use one or two objects most of the time. Note that IE does not enjoy it if you set the onreadystatechange before calling open, so make sure you keep them in the proper order.

The onreadystatechange function is now declared inline, so that we can pass an argument to xmlhttpChange. Rather than loop through the array every time we get a result, just tell it which item we want to use in the first place. Since we never remove items from the array, passing pos won't cause problems.

The xmlhttpChange function is much more compact in this version, and there's no need to construct a new xml document - you can just pass the responseXML straight through. After handling the response or dealing with an error, just set freed to 1 in order to re-use the xmlhttp object.

The whole thing is now less complicated and it re-uses xmlhttp objects. And there was much rejoicing.

Link | Comments (8)

Aug 9 2006 02:08Handling Multiple XMLHTTPRequest Objects

This is the old article - my newer, better method can be found here.

If you're using XMLHTTPRequest objects in your AJAX application and you send multiple requests simultaneously, you might notice some problems. There are plenty of examples out there to get you started, but none of them cover this issue (or at least they didn't a year ago).

[ Read more... ]

Link | Comments (5)

Aug 7 2006 22:07Welcome to Drakware

Welcome to the new and improved Drakware!

I'll be posting articles on a not-so-regular basis in this newer format from now on. Topics will cover XHTML, CSS, Javascript (including AJAX), and possibly some Win32 development, and most articles will probably be of the how-to variety.

Link | Comments (1)

Copyright © 2006 Drakware
All rights reserved.