Simultaneous ajax calls - javascript

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();

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);
}
}

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.

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.

Related

XMLHttpRequest() javascript

to resume my problem, i'm using many XMLHttpRequest() rockets, with a view to get the value (miniTable) returned by the TableRow() function. The problem is, with the alert() on the end of the TableRow() function, i'm have exactly the value that i want, but on TableContent2 variable i'm having an "Undefined" value. I don't know why!! here all the JS file that i'am using (don't care about variables and code calculating the variables). I really need your help, because i'm blocked since 3 days on that. Thank you again and good afternoon freinds.
(function() {
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
myFunction(xmlhttp);
}
};
xmlhttp.open("GET", "File1.xml", true);
xmlhttp.send();
})();
function ContentFunction(func) {
TableContent2 = TableRow();
alert(TableContent2);
}
function TableRow() {
xmlhttp3 = new XMLHttpRequest();
xmlhttp3.onreadystatechange = function() {
if (xmlhttp3.readyState == 4 && xmlhttp3.status == 200) {
texttest = myFunction2(xmlhttp3);
alert(miniTable);
return miniTable;
}
};
xmlhttp3.open("GET", "File2.xml", true);
xmlhttp3.send();
}
function myFunction2(xml) {
var xmlDoc2 = xml.responseXML;
var ObjectText;
var x = xmlDoc2.getElementsByTagName("Clip");
/*Calcule de ObjectText*/
alert(ObjectText);
return ObjectText;
}
function myFunction(xml) {
xmlhttp2 = new XMLHttpRequest();
var xmlDoc = xml.responseXML;
var x = xmlDoc.getElementsByTagName("Film");
xmlhttp2.onreadystatechange = function() {
if (xmlhttp2.readyState == 4 && xmlhttp2.status == 200) {
myFunction2(xmlhttp2);
}
};
xmlhttp2.open("GET", "File2.xml", true);
xmlhttp2.send();
}
TableRow returns nothing. The return statement at xmlhttp3.onreadystatechange isn't in the earlier scope. Besides that, your xmlhttp3 is set to be asynchronous, then you can't directly return any information of the AJAX. Synchronous requests, which are deprecated (that's why you shouldn't use them), can be directly read, since they act like a infinite loop that breaks when the request is done (for(;xhr.readyState!==4;);, doing this manually will pause the request and the script execution forever, this is why synchronous requests have been made before.).
Synchronous requests aren't a good idea, they break interaction with entire of the page, since they pause the page/script execution. For instance, if you've a animation, it'll be paused, including event listeners.
Also, it looks like miniTable haven't been declared in any part of your code.
Consider using callback functions, they'll be stored in the TableRow scope and can be called later, with extra arguments.
This is a base:
function ContentFunction(func) {
TableRow(function(TableContent2) {
alert(TableContent2);
});
}
function TableRow(doneFnc) {
var xmlhttp3 = new XMLHttpRequest;
xmlhttp3.onreadystatechange = function() {
if (xmlhttp3.readyState === 4 && xmlhttp3.status === 200) {
var texttest = myFunction2(xmlhttp3);
/* success callback */
doneFnc(texttest);
}
};
xmlhttp3.open("GET", "File2.xml", true);
xmlhttp3.send();
}

Using a while loop to get rows using PhpExcel

I am looking to create javascript arrays with rows taken from an xlsx spread sheet using PHPExcel.
Here is my code
$document.ready({
var rows = new Array();
var vals = new Array();
var i = 0;
while(){
rows[i] = getRow(i);
vals[i] = getVal(i);
i++;
}
});
function getRow(i){
if(window.XMLHttpRequest){
xmlhttp= new XMLHttpRequest();
}else{
xmlhttp= new ActiveXObject('Microsoft.XMLHTTP');
}
xmlhttp.onreadystatechange = function (){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
return xmlhttp.responseText;
}
}
xmlhttp.open('GET', 'data.inc.php?x='+i, true);
xmlhttp.send();
}
function getVal(i){
if(window.XMLHttpRequest){
xmlhttp= new XMLHttpRequest();
}else{
xmlhttp= new ActiveXObject('Microsoft.XMLHTTP');
}
xmlhttp.onreadystatechange = function (){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
return xmlhttp.responseText;
}
}
xmlhttp.open('GET', 'include.inc.php?x='+i, true);
xmlhttp.send();
}
I am not sure what to check for in the parameter of the while loop (Im assuming we do not know how many rows are in the spreadsheet)
Is that my only issue or this the wrong way to go about it?
Also the function getRow return the entire row and getVal returns one column that will be important elsewhere on the page.
There are different approaches you can use:
1) Synchronise your requests:
function getRow(i, rows){
...
xmlhttp.onreadystatechange = function (){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
if xmlhttp.responseText != '' {
rows[i] = xmlhttp.responseText;
getRow(i+1, rows)
} else {
// call function that works with rows.
}
}
}
...
}
This function is only called with getRows(0, rows) (no loop!).
This is definitely the slowest approach because every request is started as soon as the previous request has finished.
2) Send number of rows first:
You could send the number of rows with the first or with each request, so javascript knows how many rows there are. Then you can loop over the rows and create asynchronous calls as you do now.
3) Send all rows at once:
I don't know your use case, but it looks like a waste of time to call every row separately. Why not make one call and return all of the data at once with linebreaks as delimiters (or something else suiting your data). If your data is really huge you could still break down the data into large chunks and combine this with option 1 or option 2.
4) Send data at page load:
Not sure if this is an option it looks like it is since you execute your function on document.ready. You could consider writing your data into a special hidden div and read the data from there (with javascript) into your variables. That way you avoid all the ajax calls. This is probably the fastest if you want to load all data anyway.
Note: you might consider using jQuery which makes working with ajax a lot easier. Check jQuery get for example.

Is there a way to change a global variable on the document in the call back xmlHttpReq.onreadystatechange?

I am pretty new to the AJAX thing, but now I want to set some value to a global variable on the document based on status changed in the call back function xmlHttpReq.onreadystatechange, I used something like
function checkFile(fileUrl) {
var xmlHttpReq = false;
var self = this;
// Mozilla/Safari
if (window.XMLHttpRequest) {
self.xmlHttpReq = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject) {
self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
}
if(self.xmlHttpReq == null){
alert("Your browser does not support XMLHTTPReq")
}
self.xmlHttpReq.open('HEAD', fileUrl, true);
self.xmlHttpReq.onreadystatechange = function() {
if (self.xmlHttpReq.readyState == 4) {
if (self.xmlHttpReq.status == 200) {
window.rett = 1;
//alert(window.rett);
} else if (self.xmlHttpReq.status == 404) {
window.rett = 0;
//alert(window.rett);
}
}
}
self.xmlHttpReq.send();
}
and I use the checkFile in a jquery template like this:
<script id="resultTemplate" type="text/x-jquery-tmpl">
<li> ${checkFile(link)} <b> {{if window.rett == 1 }} ${link} {{/if}}</b> </li>
</script>
but when I access the window.rett in a Jquery template, it says undefined...
The reason I want to get the global value is that I want to generate different GUI based on the global value.
Maybe this is not a good practice of using global variable? Any suggestion is appreciated.
Most likely because by the time you tried accessing it, the AJAX request has not completed yet (has not reached state 4), thus your global hasn't been declared (or if it was, it still contains the value of the previous result)
I suggest you use your template from within the callback. That way, by the time your template checks for the value, the value is already there:
function yourAjaxFunction(arg1, arg2,...,callback){
//all AJAX setup codes here
if (self.xmlHttpReq.readyState === 4) {
if (self.xmlHttpReq.status === 200) {
//sending the callback a 1
callback(1);
} else if (self.xmlHttpReq.status === 404) {
//sending the callback a 1
callback(0);
}
}
//AJAX send codes
}
//how you should use it
yourAjaxFunction(arg1,arg2,...,function(rett){
//use rett here
//parse template here
});

Form submit using Ajax

I need to submit the a form using Ajax with POST method.The code is as follows,
function persistPage(divID,url,method){
var scriptId = "inlineScript_" + divID;
var xmlRequest = getXMLHttpRequest();
xmlRequest.open("POST",url,true);
xmlRequest.onreadystatechange = function(){
alert(xmlRequest.readyState + " :" + xmlRequest.status);
if (xmlRequest.readyState ==4 || xmlRequest.status == 200)
document.getElementById(divID).innerHTML=xmlRequest.responseText;
};
xmlRequest.open("POST", url, false);
alert(xmlRequest.readyState);
xmlRequest.send(null);
}
but the form is not submitting(request is not executed or no data posted).How to submit the form using Ajax.
Thanks
There's a few reasons why your code doesn't work. Allow me to break it down and go over the issues one by one. I'll start of with the last (but biggest) problem:
xmlRequest.send(null);
My guess is, you've based your code on a GET example, where the send method is called with null, or even undefined as a parameter (xhr.send()). This is because the url contains the data in a GET request (.php?param1=val1&param2=val2...). When using post, you're going to have to pass the data to the send method.
But Let's not get ahead of ourselves:
function persistPage(divID,url,method)
{
var scriptId = "inlineScript_" + divID;
var xmlRequest = getXMLHttpRequest();//be advised, older IE's don't support this
xmlRequest.open("POST",url,true);
//Set additional headers:
xmlRequest.setRequestHeader('X-Requested-With', 'XMLHttpRequest');//marks ajax request
xmlRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencode');//sending form
The first of the two headers is not always a necessity, but it's better to be safe than sorry, IMO. Now, onward:
xmlRequest.onreadystatechange = function()
{
alert(xmlRequest.readyState + " :" + xmlRequest.status);
if (xmlRequest.readyState ==4 || xmlRequest.status == 200)
document.getElementById(divID).innerHTML=xmlRequest.responseText;
};
This code has a number of issues. You're assigning a method to an object, so there's no need to refer to your object using xmlRequest, though technically valid here, this will break once you move the callback function outside the persistPage function. The xmlRequest variable is local to the function's scope, and cannot be accessed outside it. Besides, as I said before, it's a method: this points to the object directlyYour if statement is a bit weird, too: the readystate must be 4, and status == 200, not or. So:
xmlRequest.onreadystatechange = function()
{
alert(this.readyState + " :" + this.status);
if (this.readyState === 4 && this.status === 200)
{
document.getElementById(divID).innerHTML=this.responseText;
}
};
xmlRequest.open("POST", url, false);
alert(xmlRequest.readyState);//pointless --> ajax is async, so it will alert 0, I think
xmlRequest.send(data);//<-- data goes here
}
How you fill the data is up to you, but make sure the format matches the header: in this case 'content type','x-www-form-urlencode'. Here's a full example of just such a request, it's not exactly a world beater, since I was in the process of ditching jQ in favour of pure JS at the time, but it's serviceable and you might pick up a thing or two. Especially take a closer look at function ajax() definition. In it you'll see a X-browser way to create an xhr-object, and there's a function in there to stringify forms, too
POINTLESS UPDATE:
Just for completeness sake, I'll add a full example:
function getXhr()
{
try
{
return XMLHttpRequest();
}
catch (error)
{
try
{
return new ActiveXObject('Msxml2.XMLHTTP');
}
catch(error)
{
try
{
return new ActiveXObject('Microsoft.XMLHTTP');
}
catch(error)
{
//throw new Error('no Ajax support?');
alert('You have a hopelessly outdated browser');
location.href = 'http://www.mozilla.org/en-US/firefox/';
}
}
}
}
function formalizeObject(form)
{//we'll use this to create our send-data
recursion = recursion || false;
if (typeof form !== 'object')
{
throw new Error('no object provided');
}
var ret = '';
form = form.elements || form;//double check for elements node-list
for (var i=0;i<form.length;i++)
{
if (form[i].type === 'checkbox' || form[i].type === 'radio')
{
if (form[i].checked)
{
ret += (ret.length ? '&' : '') + form[i].name + '=' + form[i].value;
}
continue;
}
ret += (ret.length ? '&' : '') + form[i].name +'='+ form[i].value;
}
return encodeURI(ret);
}
function persistPage(divID,url,method)
{
var scriptId = "inlineScript_" + divID;
var xmlRequest = getXhr();
xmlRequest.open("POST",url,true);
xmlRequest.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xmlRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencode');
xmlRequest.onreadystatechange = function()
{
alert(this.readyState + " :" + this.status);
if (this.readyState === 4 && this.status === 200)
{
document.getElementById(divID).innerHTML=this.responseText;
}
};
xmlRequest.open("POST", url, false);
alert(xmlRequest.readyState);
xmlRequest.send(formalizeObject(document.getElementById('formId').elements));
}
Just for fun: this code, untested, but should work allright. Though, on each request the persistPage will create a new function object and assign it to the onreadystate event of xmlRequest. You could write this code so that you'll only need to create 1 function. I'm not going into my beloved closures right now (I think you have enough on your plate with this), but it's important to know that functions are objects, and have properties, just like everything else:Replace:
xmlRequest.onreadystatechange = function()
{
alert(this.readyState + " :" + this.status);
if (this.readyState === 4 && this.status === 200)
{
document.getElementById(divID).innerHTML=this.responseText;
}
};
With this:
//inside persistPage function:
xmlRequest.onreadystatechange = formSubmitSuccess;
formSubmitSuccess.divID = divID;//<== assign property to function
//global scope
function formSubmitSuccess()
{
if (this.readyState === 4 && this.status === 200)
{
console.log(this.responseText);
document.getElementById(formSubmitSuccess.divID).innerHTML = this.responseText;
//^^ uses property, set in persistPAge function
}
}
Don't use this though, as async calls could still be running while you're reassigning the property, causing mayhem. If the id is always going to be the same, you can, though (but closures would be even better, then).
Ok, I'll leave it at that
This code can let you understand. The function SendRequest send the request and build the xmlRequest through the GetXMLHttpRequest function
function SendRequest() {
var xmlRequest = GetXMLHttpRequest(),
if(xmlRequest) {
xmlRequest.open("POST", '/urlToPost', true)
xmlRequest.setRequestHeader("connection", "close");
xmlRequest.onreadystatechange = function() {
if (xmlRequest.status == 200) {
// Success
}
else {
// Some errors occured
}
};
xmlRequest.send(null);
}
}
function GetXMLHttpRequest() {
if (navigator.userAgent.indexOf("MSIE") != (-1)) {
var theClass = "Msxml2.XMLHTTP";
if (navigator.appVersion.indexOf("MSIE 5.5") != (-1)) {
theClass = "Microsoft.XMLHTTP";
}
try {
objectXMLHTTP = new ActivexObject(theClass);
return objectXMLHTTP;
}
catch (e) {
alert("Errore: the Activex will not be executed!");
}
}
else if (navigator.userAgent.indexOf("Mozilla") != (-1)) {
objectXMLHTTP = new XMLHttpRequest();
return objectXMLHTTP;
}
else {
alert("!Browser not supported!");
}
}
take a look at this page. In this line: req.send(postData); post data is an array with values that should be posted to server. You have null there. so nothing is posted. You just call request and send no data. In your case you must collect all values from your form, as XMLHTTPRequest is not something that can simply submit form. You must pass all values with JS:
var postData = {};
postData.value1 = document.getElementById("value1id").value;
...
xmlRequest.send(postData);
Where value1 will be available on server like $_POST['value'] (in PHP)
Also there might be a problem with URL or how you are calling persistPage. persistPage code looks ok to me, but maybe I'm missing something. Also you can take a look if you have no errors in console. Press F12 in any browser and find console tab. In FF you may need to install Firebug extention. Also there you will have Network tab with all requests. Open Firebug/Web Inspector(Chrome)/Developer Toolbar(IE) and check if new request is registered in its network tab after you call persistPage.
I found you've invoked the
xmlRequest.open()
method twice, one with async param as true and the other as false. What exactly do you intend to do?
xmlRequest.open("POST", url, true);
...
xmlRequest.open("POST", url, false);
If you want to send asynchronous request, pls pass the param as true.
And also, to use 'POST' method, you'd better send the request header as suggested by Elias,
xmlRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencode');
Otherwise, you may still get unexpected issues.
If you want a synchronous request, actually you may handle the response directly right after you send the request, just like:
xmlRequest.open("POST", url, false);
xmlRequest.send(postData);
// handle response here
document.getElementById(scriptId).innerHTML = xmlRequest.responseText;
Hope this helps.

Strange javascript behavior - multiple active XMLHttpRequests at once? Long running scripts?

I'm attempting to issue two concurrent AJAX requests.
The first call (/ajax_test1.php) takes a very long time to execute (5 seconds or so).
The second call (/ajax_test2.php) takes a very short time to execute.
The behavior I'm seeing is that I /ajax_test2.php returns and the handler gets called (updateTwo()) with the contents from /ajax_test2.php.
Then, 5 seconds later, /ajax_test1.php returns and the handler gets called (updateOne()) with the contents from /ajax_test2.php still!!!
Why is this happening?
Code is here: http://208.81.124.11/~consolibyte/tmp/ajax.html
This line:-
req = new XMLHttpRequest();
should be:-
var req = new XMLHttpRequest();
As AnthonyWJones stated, your javascript is declaring the second AJAX object which first overwrites the req variable (which is assumed global since there is no var) and you are also overwriting the ajax variable.
You should separate your code i.e:
function doOnChange()
{
var ajax1 = new AJAX('ajax_test1.php', 'one', updateOne);
var ajax2 = new AJAX('ajax_test2.php', 'two', updateTwo);
}
function AJAX(url, action, handler)
{
if (typeof XMLHttpRequest == "undefined")
{
XMLHttpRequest = function()
{
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
throw new Error( "This browser does not support XMLHttpRequest." )
};
}
url = url + '?action=' + action + '&rand=' + Math.random()
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState == 4)
{
if (req.status == 200)
{
alert('' + handler.name + '("' + req.responseText + '") ')
handler(req.responseText)
}
}
}
req.open("GET", url, true);
req.send(null);
}
Regards
Gavin
Diodeus and Mike Robinson:
You guys didn't read my post fully. I know that one of the pages takes longer to execute than the other. That is the expected behavior of each page.
HOWEVER if you read my original post, the problem is that the callback for both pages ends up getting called with the HTML contents of the first page only.
AnthonyWJones and Gavin:
Thanks guys! That works like a charm! I guess I need to brush up on my Javascript!

Categories

Resources