What's wrong with AJAX guides?

Most Ajax guides available online would tell you how Ajax is our way to the asynchronus client programming. Follow that with an example of how to build Ajax requests with details upto callback management. The poor reader will grab the code and paste it in his/her application and will find it working. After his/her application grows things will start to miss behave. What went wrong? The poor fellow who had little to no knowledge of Javascript (and may be shunned it off earlier as a languange for those who can't do real programming) didnt give the script a good look trying to figure out what's going on first.

Here's an example from developer.apple.com :

var req;

function loadXMLDoc(url) {
req = false;
// branch for native XMLHttpRequest object
if(window.XMLHttpRequest) {
try {
req = new XMLHttpRequest();
} catch(e) {
req = false;
}
// branch for IE/Windows ActiveX version
} else if(window.ActiveXObject) {
try {
req = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
try {
req = new ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {
req = false;
}
}
}
if(req) {
req.onreadystatechange = processReqChange;
req.open("GET", url, true);
req.send("");
}
}

function processReqChange() {
// only if req shows "loaded"
if (req.readyState == 4) {
// only if "OK"
if (req.status == 200) {
// ...processing statements go here...
} else {
alert("There was a problem retrieving the XML data:\n" +
req.statusText);
}
}
}
What's the problem with the above code? specially in an asynchronus environment?

The variable req (which is used as the XMLHTTPRequest object) is defined globally!! So when our friend tries to instantiate a new request before the current one finishes it will overwrite it and you will lose any reference to the old request.

But why did we have a global variable in the first place? If it's so bad, why didnt we make it local tothe loadXMLDoc funciton?

Simple, because the call back function needs to access this variable. And if it cannot be found in its scope it will look at it in the global scope.

Closures any one?

this can easily be solved by defining the call back function as an inner function to the loadXMLDoc() function and declaring the variable req as local to this function
function loadXMLDoc(url) {
var req = false;
// branch for native XMLHttpRequest object
if(window.XMLHttpRequest) {
try {
req = new XMLHttpRequest();
} catch(e) {
req = false;
}
// branch for IE/Windows ActiveX version
} else if(window.ActiveXObject) {
try {
req = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
try {
req = new ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {
req = false;
}
}
}
if(req) {
req.onreadystatechange = processReqChange;
req.open("GET", url, true);
req.send("");
}


var processReqChange = function() {
// only if req shows "loaded"
if (req.readyState == 4) {
// only if "OK"
if (req.status == 200) {
// ...processing statements go here...
} else {
alert("There was a problem...");
}
}
}

}


All we needed to do is declare req as a local variable by adding the var keyword and removing the global declaration.

This way each request will spawn a new req object which will be accessed by the callback function and will be garbage collected after the callback function returns (some browsers - namely older versions of internet explorer - might leak memory here as they deal very badly with closures)