As most people know internet explorer has a maximum capacity of 2 http connections at one time, so when more than 2 ajax calls were made on a page at the same time one of the ajax requests was being forgotten, as this was an issue for one fo my clients I built this object handler, it’s using the library dojo but only for basic queries and the ajax call, you can replace these with jQuery selectors and the jQuery load function, I just thought I’d show you the principle of what I have built.



/*******************************************************************************
 * This object provides testing for connections
 * awl is my sites main obj
 ******************************************************************************/

awl.connections = new ( function() {
  var maxconnections = 5;//default
  if(dojo.isIE){
    var maxconnections = 2;//ie default
  }
  var index = 0;
  this.callList = {} //stored calls
  this.countRunning = 0;
  
  //public function
  this.init = function(args,calltype,callcat,name,uId) {
    
    //set up call obj
    index++;    
    awl.connections.callList[index] = {
        'args':args,
        'calltype':calltype,
        'callcat':callcat,
        'name':name,
        'uId':uId
        }
    
    
    
    //call logic
    if(callcat == 'mustqueue'){
      //check for other must queues, if so flag it as this call next
      var queueIndex = checkIfMustQueueRunning(name, index); 
      if(!queueIndex) {
        //no must calls running call normally  
        makeCall(index);
      } 
    } else if(callcat == 'supercede'){  
      //check for other supercedes running
      var sameIndex = checkIfSimilarRunning(name); 
      if(sameIndex) {
        //set cancelled and cancel old supercede call
        awl.connections.callList[sameIndex].cancelled = true;
        awl.connections.callList[sameIndex].handle.cancel();
        //now make call
        makeCall(index);
      } else if(checkConnections()){
        makeCall(index);
      }
    } else if(callcat != 'cancellable' && !checkConnections()){
      //check if cancellable connections available
      var cIndex = checkIfCancellableRunning(); 
      if(cIndex) {
        //set cancelled and cancel old supercede call
        awl.connections.callList[cIndex].cancelled = true;
        awl.connections.callList[cIndex].handle.cancel();
        //now make call
        makeCall(index);
      }
    } else if(checkConnections()){
      //make call
      makeCall(index);      
    }
  }
  
  this.finalise = function(refId){
    
    
    //decrement count
    awl.connections.countRunning--;    
    
    //remove state indicates what to do next after removing the call, returns obj
    // state 1 = make next in queue if it exists
    // state 2 = make next must queue, also provides index of next must queue
    // state 3 = call already made as has been cancelled, do nothing
    var removeState = removeCall(refId);
    
    //if connection was cancelled call already made, if not make call
    if(removeState.state == 1){
      //now check for queued calls
      //get next in the queue
      var nextIndex = getNextCallIndex();
      if(nextIndex){
        
        makeCall(nextIndex);
      }
    } else if(removeState.state == 2){
      
      makeCall(removeState.nextIndex);
    } else {
      //do nothing
    }
    
    
  }
  this.getUniqueId = function() {
    // create unique id
    return 'con_' + index;    
  }
  
  function checkIfMustQueueRunning(name,index) {
    var ma = awl.connections.callList, ind = null;
    for(var x in ma){
      if(ma[x].callcat == 'mustqueue' && ma[x].running && ma[x].name == name){
        setNextIndex(ma[x],index);      
        ind = x;
      }
    }    
    return ind;
  }
  
  function setNextIndex(rObj,index){
    if(rObj.nextIndex){
      //already got a next index so loop until next index not set
      setNextIndex(awl.connections.callList[rObj.nextIndex],index);
    } else {
      //set next index to run
      rObj.nextIndex = index;
    }
  }
  
  function checkIfCancellableRunning(n) {
    var ma = awl.connections.callList, ind = null;
    for(var x in ma){
      if(ma[x].callcat == 'cancellable' && ma[x].running){
        ind = x;
      }
    }    
    return ind;
  }
  
  function checkIfSimilarRunning(n) {
    var ma = awl.connections.callList, ind = null;
    for(var x in ma){
      if(ma[x].name == n && ma[x].running){
        ind = x;
      }
    }    
    return ind;
  }
  
  function removeCall(id){
    var ma = awl.connections.callList, oState = {};
    for(var x in ma){
      if(ma[x].uId && ma[x].uId==id){
        if(awl.connections.callList[x].cancelled){
          //flag that it was cancelled
          oState.state = 3;
        } else if (awl.connections.callList[x].nextIndex){
          oState.state = 2;
          oState.nextIndex = awl.connections.callList[x].nextIndex;
        } else {
          oState.state = 1;
        }
        //remove call
        delete awl.connections.callList[x];
      }
    }
    return oState;
  }
  function makeCall(i){
    var oCall = awl.connections.callList[i];
    if(oCall && !oCall.running){
      
      //increment count running
      awl.connections.countRunning++;
      if (oCall.calltype=="get"){
        oCall.handle = dojo.xhrGet(oCall.args);
      } else if (oCall.calltype=="post") {
        oCall.handle = dojo.xhrPost(oCall.args);
      }
      //flag as active
      oCall.running = true;
    }    
  }
  function getNextCallIndex() {
    var ma = awl.connections.callList,i=null;
    for(var x in ma){
      //if not running or not queued to be next if the lowest index      
      if(!ma[x].running && !ma[x].nextIndex){
        if(!i){
          i=x;
        } else if(x<i){
          i=x;
        }
      }      
    }
    return i;
  }
  function checkConnections() {
    //console.log("count: ",awl.connections.countRunning);
    if (awl.connections.countRunning < maxconnections){
      return true;
    } else {
      return false;
    }
  }
  
  /** for test only below */
  this.runTest = function() {
    
    fakeAjax();    
    setTimeout(function(){
      fakeAjax();
    },200);
    setTimeout(function(){
      fakeAjax();
    },300);
    setTimeout(function(){
      fakeAjax();
    },400);
    setTimeout(function(){
      fakeAjax();
    },500);
  }
  function fakeAjax(t) {
    var uId = awl.connections.getUniqueId(),
    type = t ? t : 'mustqueue';
    
    var xhrArgs = {
      url : 'SearchLookAhead?storeId=10151&catalogId=15001&langId=44&searchTerm=bat',
      handleAs : 'text',
      preventCache : true,
      load : function(d) {
        awl.connections.finalise(uId);
        console.log("fake ajax finished");
      },
      error : function(error) {
        awl.connections.finalise(uId);  
        console.log("fake ajax cancelled");
      }
    }
    //this is how to call you ajax call using the defined xhrArgs obj above
    awl.connections.init(xhrArgs,'get',type,'test',uId);
  }
  
  
  
});