Anyone working with AJAX knows the headache of dealing with HTTP Requests. They can only be done one at a time, and any one called while waiting on another leaves that request blowing in the wind. The only way to successfully handle request that can be fired off at any time, is to use a queuing system to manage the calls. I’m sure there are other recommendations out there, but I always enjoy the challenge of creating my own solutions.
Before I get into the code of my AJAX Request Queue, I want to show you the debug window. I set this up as a div with a few form fields that I can pop open at any time to show me what’s going on in the queue.

 |
Form Field “queueMsg” – A general message about the state of the queued requests. |
 |
Form Field “queueInCall” – The value of the inCall variable… where or not the HTTP Request line is busy. |
 |
Form Field “queueReadyState” – The value of the readystate variable of the current HTTP Request, if in a call. |
 |
Form Field “queueTest” – The list of calls waiting to be executed. This example shows that there are 2 pending calls, one to get some slides and another to get comments for a particular slide. |
| |
The following is the Javascript code for the queue, all contained in a .JS file called createRequestObject, which is linked on pages that need to make HTTP Requests. I’m not going to go into too much detail about the code, just the overall idea.
Setting up initial variables:
// TURN ON DEBUG WINDOW FEEDBACK
// I WILL WANT TO DISABLE THIS IN THE LIVE VERSION…
var httpTesting = true;
// SET MY REQUEST OBJECT
var http = createRequestObject();
// VARIABLE TO TRACK IF WE ARE CURRENTLY IN A CALL
var inCall = false;
// QUEUE FOR CALLS
var callToArray = new Array();
// QUEUE FOR FUNCTION TO EXECUTE WHEN CALL COMPLETE
var returnToArray = new Array();
|
Create our Request Object:
function createRequestObject() {
var reqObj;
var browser = navigator.appName;
if(browser == "Microsoft Internet Explorer"){
reqObj = new ActiveXObject("Microsoft.XMLHTTP");
isIE = true;
}else{
reqObj = new XMLHttpRequest();
}
return reqObj;
}
|
Insert calls to the Queue:
function sendCall(whereTo, returnTo){
// GET THE NEXT ARRAY ITEM AND REMOVE FROM THE ARRAY
callToArray.push(whereTo);
returnToArray.push(returnTo);
}
|
Watcher function that is called on intervals to set out queued calls based on inCall variable:
function callQueue(){
// IF WE HAVE A WAY OF MONITORING THE QUEUE, UPDATE IT
if(httpTesting){
calls = "";
for(i=0;i<callToArray.length;i++){
calls += callToArray[i] + "n";
}
document.getElementsByName("queueTest")[0].value = calls;
document.getElementsByName("queueInCall")[0].value = inCall;
document.getElementsByName("queueReadyState")[0].value = http.readyState;
}
// CHECK THE QUEUE AND SEND THE NEXT CALL IN LINE
if(!inCall && callToArray.length > 0){
// DO WE HAVE ANYTHING IN THE QUEUE?
if(callToArray.length > 0){
// WE DO, SO GET THE FIRST ITEM IN THE CALL ARRAY AND REMOVE IT
whereTo = callToArray.shift();
returnTo = returnToArray.shift();
// SEND THAT CALL
doCall(whereTo, returnTo);
}else{
// UPDATE DEBUG QUEUE
if(httpTesting){
document.getElementsByName("queueMsg")[0].value = "no items in queue.";
}
}
}else{
// UPDATE DEBUG QUEUE
if(httpTesting){
if(inCall){
document.getElementsByName("queueMsg")[0].value = "currently in a call.";
}else{
document.getElementsByName("queueMsg")[0].value = "no items in queue.";
}
}
}
}
|
If we are not currently in a call and have a pending request, the call URL is sent here:
function doCall(whereTo, returnTo){
inCall = true;
http.open('get', whereTo);
// DO WE HAVE A FUNCTION TO CALL ONCE CALL IS COMPLETED?
if(returnTo.length > 0){
eval("http.onreadystatechange = "+returnTo);
}
// SEND CALL
http.send(null);
}
|
This is a generic return function intended to just clear the inCall variable when we have a call type that we don’t need/expect a response from:
function hr_inCall(){
if(http.readyState == 4){
inCall = false;
}
}
|
And finally, to start the Queue engine, we have:
var queueWatcher = setInterval(callQueue, 100);
|
All that together successfully runs my Request Queue and gives me the ability to monitor it. A pause button would be a nice addition, but I haven’t had time to implement it. However, it would simply need to clear the queueWatcher interval on pause and restart it on play.
Finally, for any page that needs to make a call, for example, a log in, I would just have the submit button call a function that gathers the data and sends it to the queue, as such:
function checkLogin(){
username = document.getElementsByName("loginEmail")[0].value;
password = document.getElementsByName("loginPassword")[0].value;
document.getElementById("loginSubmit").innerHTML = "Checking Login...";
sendCall("req/getLogin.php?username=" + username + "&password=" + password, "hr_checkLogin");
}
|
You will notice when I sendCall, I have “hr_checkLogin” as the second parameter, which, once the call is complete, will call:
function hr_checkLogin(){
if(http.readyState == 4){
inCall = false;
response = http.responseText
if(response != "0"){
document.getElementById("loginArea").innerHTML = "Login successful. Welcome back. <A href='projects.php'>Projects</a>";
}else{
document.getElementById("loginSubmit").innerHTML = "<font color='red'>Login Failed</font>";
}
}
}
|
The important thing is to always set inCall to false once your call is complete, or the next request will never be processed.
Like I said, there may be better solutions out there, but I’m a big fan of building my own, which always helps me to become a better programmer.
Any thoughts?
Like this:
Be the first to like this post.
This entry was posted on October 28, 2006 at 6:07 pm and is filed under Code. You can follow any responses to this entry through the RSS 2.0 feed.
You can leave a response, or trackback from your own site.
March 30, 2007 at 8:36 am |
Thanks for this! Exactly what I needed. Works straight out the box. Helped me to understand what is going on, being the ajax noob that I am.
May 11, 2007 at 12:49 am |
Good example. Works great. Exactly what i required. Your descriptions adds values to your example. Keep Going…!!!
September 7, 2007 at 4:07 am |
“Like I said, there may be better solutions out there, but I’m a big fan of building my own, which always helps me to become a better programmer.”
Its not always true though
since you are in your own sandbox …..its good to look at other people solutions so you wont reinvent the wheel
September 7, 2007 at 1:13 pm |
This is a pretty good solution! I spent some time looking for something similar but couldn’t really find anything. I used your ideas and made a nice AjaxManager object using good old prototype.
December 4, 2007 at 12:20 am |
[...] uzak duruyorsanız, bazı durumlarda XMLHttpRequest() istemlerini bir iş kuyruğu ile yönetmek zorunda [...]
December 12, 2007 at 2:30 am |
Hi. I’ve made a serious debt and I really need to do something about that. I think I should apply for a new credit card now, when my credit rating is so bad but I do not see any other way out except killing off my credit card debt with a new credit card. I believe it is possible to do if I pay all my bills duly in full.
trans unioin credit bureau
G7tb8Hjk
February 19, 2008 at 7:25 pm |
I may be a little slow but i cant get this working at all. I dont know if im doing anything wrong but im not getting any response.
March 6, 2008 at 10:46 am |
Can I have the complete source code for this to work.
April 3, 2008 at 3:00 am |
I am trying to make an ajax validation form (to validate int for phone number) using this query.But failed. may i ask your help? my codes are
function insertUserReply() {
if(http.readyState == 4){
var response = http.responseText;
if(response == 0){
document.getElementById(‘msg’).innerHTML = ‘Please fill all required fields!’;
}
if else (parseInt(document.forms[0].Telephone.value) != document.forms[0].Telephone.value) {
document.getElementById(‘msg’).innerHTML = ‘Please enter a telephone number, numbers only’;
}
else {
container = document.getElementById(‘mylist’);
new_element = document.createElement(‘li’);
new_element.innerHTML = response;
container.insertBefore(new_element, container.firstChild);
lastRecord=document.getElementById(‘lastRecord’).value;
new_element.setAttribute(‘id’, lastRecord);
document.getElementById(‘msg’).innerHTML = “Customer added!”;
}
May 13, 2008 at 3:24 pm |
i wish u could pass a user data as a parameter with the returnTo callback function.
by this u will be able to distinguish between calls
August 15, 2008 at 4:19 am |
NTT Says:
May 13, 2008 at 3:24 pm
i wish u could pass a user data as a parameter with the returnTo callback function.
by this u will be able to distinguish between calls
————————————————————————————
I found that I could set an id property on the request and return it to my response handler very simply with the following
xmlHttp = new XMLHttpRequest();
xmlHttp.id = this.id;
xmlHttp.name = this.name;
if(xmlHttp.readyState==4)
{
HandleResponse( xmlHttp.responseText , xmlHttp.id, xmlHttp.name );
}
I couldn’t get prototype to work on the xmlHttpRequest object (which could be a problem with IE7?) so to hold other information with the request I used the request objects “name” property and set it to be a list of delimitted values then use string.split in my response handler.
April 15, 2009 at 4:46 pm |
i’m trying to download for files in different http requests can you help
me do that
October 9, 2009 at 5:16 am |
Hi
I hvae problems listning to incoming http requests from a push server.
Can you help please?
Phone Status requests are pushed / send to my using http. But I do not know how to get it out to a web.
Best Regards
Maali
November 24, 2009 at 10:31 am |
Hi,
thanks a lot for this nice code!
My question is: is there a chance to set and monitor timeout?
Cheers DF
May 6, 2010 at 11:23 pm |
Thank You for nice piece of code. I am not a regular Web Programmer but interested in learning. Have read about issues of invoking a CROSS domain XMLhttpRequest object through JavaScript and it’s limitations on various types of Browsers.
Am talking about a REMOTE Client requesting a Page to be back to his PC from a cross domain server for his own further analysis.
Would highly appreciate if you could explain with examples and possible checks/ exceptions handling , so that Remote Client knows , about what is going on or any issue if there.
Thanks again,
Sanjib
November 12, 2010 at 12:23 am |
Can I have the complete source code for this to work.