0

I'm trying to make 2 (or more) ajax calls simultaneously. I don't want to use jQuery, only pure JavaScript.

Most of the time, it works. data1 will output data from sample.com/ajax1 and data2 will output data from sample.com/ajax2, but sometimes (1 from 10) the second AJAX call will display result from the first one.

Why is this happening? Both AJAX requests are requesting data from the same domain, but from different URLs. Is there any way how to prevent this behavior?

Here is the script:

// First AJAX
var xmlhttp1;

// Second AJAX
var xmlhttp2;

if (window.XMLHttpRequest) {
    xmlhttp1 = new XMLHttpRequest();
} else {
    xmlhttp1 = new ActiveXObject("Microsoft.XMLHTTP");
}

xmlhttp1.onreadystatechange = function() {
    if (xmlhttp1.readyState == 4 && xmlhttp1.status == 200) {
        data = JSON.parse(xmlhttp1.responseText);
        console.log('data1: ' + data);
    }
}

xmlhttp1.open("GET", "http://sample.com/ajax1", true);
xmlhttp1.send();

if (window.XMLHttpRequest) {
    xmlhttp2 = new XMLHttpRequest();
} else {
    xmlhttp2 = new ActiveXObject("Microsoft.XMLHTTP");
}

xmlhttp2.onreadystatechange = function() {
    if (xmlhttp2.readyState == 4 && xmlhttp2.status == 200) {
        data = JSON.parse(xmlhttp2.responseText);
        console.log('data2: ' + data);
    }
}

xmlhttp2.open("GET", "http://sample.com/ajax2", true);
xmlhttp2.send();
filip.karas
  • 596
  • 2
  • 11
  • 27
  • 3
    _"but sometimes (1 from 10) the second AJAX call will display result from the first one."_ Because they're asynchronous. There's zero guarantee that one AJAX call sent before a second AJAX call will return before the second call returns. – j08691 Sep 10 '13 at 20:21
  • 2
    "var data" is the problem.... – cocco Sep 10 '13 at 20:22
  • Try using `data1` and `data2` instead of `data`, as they're both sharing the same variable. – Pete Sep 10 '13 at 20:22
  • @cocco That makes no sense. The OP is `console.log`ging it as soon as they set it. There's no way the callbacks are interfering with each other. It would be a different story if they were trying to access `data` **outside** of this code and expecting it to hold the right value...but that wouldn't make sense and the OP doesn't seem to be doing that – Ian Sep 10 '13 at 20:29
  • 2
    You can hit async issues from having a global `data` but the way it is written the console should always log the correct `data`. JSON.parse is a synchronous method. – pllee Sep 10 '13 at 20:30
  • as it's global there is always a chance that it logs the wrong data... especially if he tests on localhost wehre it loads very fast.anyway create one ajax function and an array that contains the requests and delete them on complete. – cocco Sep 10 '13 at 20:32
  • @pllee Exactly, very well stated. I think the problem is what j08691 (the first comment) said - that the OP expects the calls to come back in the order they were sent, which definitely isn't guaranteed – Ian Sep 10 '13 at 20:33
  • 1
    @cocco No, not true at all. The `console.log` happens immediately after the `data =`, both of which are synchronous (inside of their respective callbacks). So there's no reason anything like that would happen – Ian Sep 10 '13 at 20:33
  • 1
    @cocco in this case it will never log the wrong data. JS is single threaded, even thought the global `data` can change value at any time the next statement will always log the correct `data` to the console. @Ian is correct. – pllee Sep 10 '13 at 20:34
  • so why it logs the wrong data? – cocco Sep 10 '13 at 20:36
  • 1
    @plee and Ian, what _else_ would be causing the behavior the OP is encountering then? – Jedediah Sep 10 '13 at 20:38
  • looks like that was the problem.... yeah anyway i added a ajax script that handels multiple requests. – cocco Sep 10 '13 at 20:55
  • 1
    @Jedediah @cocco I assume the code we are seeing is not exactly the same as the issue they are describing. Adding `var` in front of `data` may fix the problem but not the code that was presented here. There is never a case (assuming the backend works) where the problem that the OP is describing can be reproduced with the code provided. – pllee Sep 10 '13 at 21:00

3 Answers3

1

First of all, I recomment wrapping your xmlHttpRequest generation/handling in a function, so you don't duplicate code that much.

The problem you have there is that the data variable is global, so both ajax callbacks are using the same variable. You can fix it using the var keyword in both calls.

xmlhttp2.onreadystatechange = function() {
    if (xmlhttp2.readyState == 4 && xmlhttp2.status == 200) {
        var data = JSON.parse(xmlhttp2.responseText);
        console.log('data2: ' + data);
    }
}
mati
  • 5,218
  • 3
  • 32
  • 49
1

Because you're not properly encapsulating data. The way you have it written, data is a global object, so it's available to be modified by either ajax call. Since ajax calls are asynchronous, this will lead to unpredictable values for data.

Jedediah
  • 1,916
  • 16
  • 32
0

The problem is probably because you forgot to define data inside your function

anyway with this function you can create multiple requests and have more control over them..

var req={};
function ajax(a){
 var i=Date.now()+((Math.random()*1000)>>0);
 req[i]=new XMLHttpRequest;
 req[i].i=i;
 req[i].open('GET',a);
 req[i].onload=LOG;
 req[i].send();
}
function LOG(){
 console.log(this.i,this.response);
 delete req[this.i];//clear
}
window.onload=function(){
 ajax('1.html');
 ajax('2.html');
 ajax('3.html');
}

uses xhr2... you need to modify the code to make it work with older browsers.

cocco
  • 16,442
  • 7
  • 62
  • 77