views:

277

answers:

4

I have an issue, mainly with IE.

I need to be able to handle n queries one after another. But If I simply call my function below in a for loop IE does some strange things (like loading only so many of the calls). If I use an alert box it proves that the function gets all of the calls, and surprisingly IT WORKS!

My guess is that IE needs more time than other browsers, and the alert box does just that.

Here is my code:

 var Ajax = function(all) {
  this.xhr = new XMLHTTPREQUEST(); // Function returns xhr object/ activeX
  this.uri = function(queries) { // Takes an object and formats query string
   var qs = "", i = 0, len = size(queries);
   for (value in queries) {
    qs += value + "=" + queries[value];
    if (++i <= len) { qs += "&"; }
   }
   return qs;
  };
  xhr.onreadystatechange = function() { // called when content is ready
   if (this.readyState === 4) {
    if (this.status === 200) {
     all.success(this.responseText, all.params);
    }
    this.abort();
   }
  };
  this.post = function() { // POST
   xhr.open("POST", all.where, true);
   xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
   xhr.send(uri(all.queries));
  };
  this.get = function() { // GET
   xhr.open("GET", all.where + "?" + uri(all.queries), true);
   xhr.send();
  };
  if (this instanceof Ajax) {
   return this.Ajax;
  } else {
   return new Ajax(all);
  }
 };

This function works perfectly for a single request, but how can I get it to work when called so many times within a loop?

+4  A: 

I think the problem might be related to the 2 concurrent connections limit that most web browsers implement.

It looks like the latency of your web service to respond is making your AJAX requests overlap, which in turn is exceeding the 2 concurrent connections limit.

You may want to check out these articles regarding this limitation:

This limit is also suggested in the HTTP spec: section 8.14 last paragraph, which is probably the main reason why most browsers impose it.

To work around this problem, you may want to consider the option of relaunching your AJAX request ONLY after a successful response from the previous AJAX call. This will prevent the overlap from happening. Consider the following example:

function autoUpdate()
{
    var ajaxConnection = new Ext.data.Connection();

    ajaxConnection.request(
    {
        method:         'GET',
        url:            '/web-service/', 

        success: function(response) 
        {
            // Add your logic here for a successful AJAX response.
            // ...
            // ...

            // Relaunch the autoUpdate() function in 100ms. (Could be less or more)
            setTimeout(autoUpdate, 100);
        }
    }
}

This example uses ExtJS, but you could very easily use just XMLHttpRequest.

Daniel Vassallo
Not only this, but when you start a second request using the SAME object the previous request is aborted.
Paulo Santos
The spec comment is a suggestion, not a standard. You are free to ingore it.
No Refunds No Returns
@No Refunds No Returns: Thanks... Rephrased my answer to indicate it as a "suggestion".
Daniel Vassallo
A: 

Given that the limit to a single domain is 2 concurrent connections in most browsers, it doesn't confer any speed advantage launching more than 2 concurrent requests. Launch 2 requests, and dequeue and launch another each time one completes.

spender
A: 

I'd suggest throttling your requests so you only have a few (4?) outstanding at any given time. You're probably seeing the result of multiple requests being queued and timing out before your code can handle them all. Just a gess though. We have an ajax library that has built-in throttling and queues the requests so we only have 4 outstanding at any one time and don't see any problems. We routinely q lots per page.

No Refunds No Returns
A: 

Your code looks like it's put together using the constructor pattern. Are you invoking it with the new operator like var foo = new Ajax(...) in your calling code? Or are you just calling it directly like var foo = Ajax(...) ?

If the latter, you're likely overwriting state on your later calls. It looks like it's designed to be called to create an object, on which the get/post methods are called. This could be your problem if you're "calling it within a loop" as you say.

quixoto
I use the new operator, and it is not supposed to return an object. It does not override, as all other browsers have no issue here.Syntax for calling it would look like this:Ajax({where : 'somewhere.php',queries : {input : "Howdy"},success : function(response) { alert(response); },params : []}).get();
Tom
OK. That part's OK then. The other thing that looks goofy to me is the scoping on the "xhr" and "uri" variables. You define them in the constructor as this.xhr and this.uri, but you access them later as bare "xhr" and "uri". I believe those should default to global scope (or whatever's outside). Not sure if things like that are def'd in global scope already. But if this works fine in other browsers, then it seems unlikely to be a language semantics issue, as IE is generally pretty consistent with other browsers on pure JS.
quixoto
"IE is generally pretty consistent with other browsers on pure JS"...this.i = " am not to sure about.";I thought the very same thing... unfortunately nothing changes. The whole issue of making "real objects" in JS and doing something like `var that = this;` is just for design, they all do nearly the same thing.
Tom