I'm writing a program to generate a random number in php, return it to a webpage and plot it on a graph. I've been debugging it a little and have noticed that when I call the request function, the webpage goes through the rest of the caller function before using returning the data from PHP. I need to get the data from the request and return it to the caller, then move on forward with the data I received from the request.
Here's the part of the caller function that keeps track in the console:
function plotData(dataSet) {
var x = xScale+20; // 20 = margin length
var y = 260; //origin of graph
getRequest();
console.log("x = "+x);
context.beginPath();
x=x+xScale; //Move along the xAxis
console.log("dataSet = "+dataSet[0]+", "+dataSet[1]);
...
}
And here's my PHP request:
function getRequest()
{
var request;
if (window.XMLHttpRequest)
{ // Mozilla, Safari, IE7+ ...
request = new XMLHttpRequest();
}
else if (window.ActiveXObject)
{ // IE 6 and older
request = new ActiveXObject("Microsoft.XMLHTTP");
}
request.onreadystatechange = function()
{
console.log('onReady');
if (request.readyState === XMLHttpRequest.DONE)
{
if (request.status === 200)
{
random = request.responseText;
random = parseInt(random);
random = random/100;
random = random.toFixed(2);
console.log("random = " +random);
data[1] = random;
console.log("data = "+data[0]+", "+data[1]);
}
else
{
alert ('There was a problem with the request');
}
}
}
request.open("GET", "external.php", true);
request.send();
}
And finally the console log:
onReady
x = 31.21951219512195
dataSet = 10, 10
onReady (x3)
random = 10.25
data = 10, 10.25
As you can see, the program is calling the all the console.log functions from plotData() before calling the functions from getRequest().
This is problematic because I need to get the information from getRequest() before I can continue with plotData().
One possible solution I just thought of is to make a 3rd function that executes after plotData() which does what I need it to do, but I feel like I should be able to handle it with the functions that I have.
Can someone explain why it goes through the caller function before the request function? And how can I fix it to wait for the request function to finish before moving forward with the caller?
Related
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();
}
I am issuing two API calls in parallel, asynchronously so I don't lock up the browser , and I am only receiving one callback.
Here is the code
/* Loop runs twice, from 0 to 1 */
for(var AccountIndex in walletForm.masterpublicKey){
/* Bunch of code, then... */
/* Construct an API call to Insight */
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://insight.bitpay.com/api/addrs/" + stringOfAddresses + "/txs?from=0&to=100", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
$scope.$apply(function () {
txListInsight.txs[AccountIndex] = ( JSON.parse(xhr.responseText));
/* Set semaphore */
txListInsight.txsReady[AccountIndex] = true;
parseTransactions(AccountIndex);
console.log(txList);
})
}
}
xhr.send();
}
I can even see the two requests in the Chrome Dev Console Network Tab and the responses are correct. Why am I only getting one callback and not two? Is my second callback overwriting the reference to the first one?
Why is there a library on the Internet called “AsyncXMLHttpRequest”? I am using AngularJS as well--shall I look into "promises"?
Another option would be to avoid the problem entirely by combining my two API requests into one, but I'm not sure what the character limit is.
I think explicitly invoking function with the current AccountIndex should work, notice the closure
var xhrs = {};
for(var AccountIndex in walletForm.masterpublicKey){
(function(AccountIndex) {
xhrs[AccountIndex] = new XMLHttpRequest();
xhrs[AccountIndex].open("GET", "https://insight.bitpay.com/api/addrs/" + stringOfAddresses + "/txs?from=0&to=100", true);
xhrs[AccountIndex].onreadystatechange = function() {
if (xhrs[AccountIndex].readyState == 4) {
$scope.$apply(function () {
txListInsight.txs[AccountIndex] = ( JSON.parse(xhrs[AccountIndex].responseText));
/* Set semaphore */
txListInsight.txsReady[AccountIndex] = true;
parseTransactions(AccountIndex);
console.log(txList);
})
}
}
xhrs[AccountIndex].send();
})(AccountIndex);
}
Hey guys I'm running an IIFE and an ajax call and it seems to not respond at all...
var $ = {
core:function(u){
return new $.httpRequest(u);
},
httpRequest:function(url){
var text;
var r = new XMLHttpRequest();
r.open("GET", url, true);
r.onreadystatechange = function () {
if (this.readyState != 4 || this.status != 200) return;
text = this.responseText;
};
r.send();
console.log(text);
return text;
}
};
Is there something silly I am missing? Just been over this a few times and I have my hands full and hope that our savvy SO members could help out. Should I place the return inside the onload?
The onreadystatechange function you assign is where you need to handle the responseText. You need to either process it there or call some function and pass it the data. Remember, the ajax call is asynchronous which means that you start it with your r.send(), your $.httpRequest() function finishes, your other javascript after it executes and then some time later the ajax call completes and calls your onreadystatechange function. At that point, all you can do is to either process the data right there in that function or call some other function and pass the data to it.
Here's one way of doing it using a callback function that you pass into your httpRequest function:
var $ = {
core:function(u){
return new $.httpRequest(u);
},
httpRequest:function(url, callback){
var r = new XMLHttpRequest();
r.open("GET", url, true);
r.onreadystatechange = function () {
if (r.readyState != 4 || r.status != 200) return;
callback(r.responseText);
};
r.send();
}
};
Example usage:
$.httpRequest("http://examplesite.com/myurl", function(data) {
// write code here to process the data
});
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.
I'm looking to setup a web page that samples data via AJAX calls from an embedded web-server. How would I set up the code so that one request doesn't overlap another?
I should mention I have very little JavaScript experience and also a compelling reason not to use external libraries of any size bigger than maybe 10 or so kilobytes.
You may want to consider the option of relaunching your AJAX request ONLY after a successful response from the previous AJAX call.
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 5 seconds.
setTimeout(autoUpdate, 5000);
}
}
}
This example uses ExtJS, but you could very easily use just XMLHttpRequest.
NOTE: If you must have an exact interval of x seconds, you would have to keep track of the time passed from when the AJAX request was launched up to the setTimeout() call, and then subtract this timespan from the delay. Otherwise, the interval time in the above example will vary with the network latency and with the time to processes the web service logic.
I suggest you use a small toolkit like jx.js (source). You can find it here: http://www.openjs.com/scripts/jx/ (less than 1k minified)
To setup a request:
jx.load('somepage.php', function(data){
alert(data); // Do what you want with the 'data' variable.
});
To set it up on an interval you can use setInterval and a variable to store whether or not a request is currently occuring - if it is, we simple do nothing:
var activeRequest = false;
setInterval(function(){
if (!activeRequest) {
// Only runs if no request is currently occuring:
jx.load('somepage.php', function(data){
activeRequest = false;
alert(data); // Do what you want with the 'data' variable.
});
}
activeRequest = true;
}, 5000); // Every five seconds
AJAX, despite the name, need not be asynchronous.
Here is the asynchronous method...
var req;
function ajax(method,url,payload,action)
{
if (window.XMLHttpRequest)
{
req = new XMLHttpRequest();
req.onreadystatechange = action;
req.open(method, url, true);
req.send(payload);
}
else if (window.ActiveXObject)
{
req = new ActiveXObject("Microsoft.XMLHTTP");
if (req)
{
req.onreadystatechange = action;
req.open(method, url, true);
req.send(payload);
}
else
{
alert("Could not create ActiveXObject(Microsoft.XMLHTTP)");
}
}
}
...but here is a synchronous equivalent...
function sjax(method,url,payload,action)
{
if (window.XMLHttpRequest)
{
req = new XMLHttpRequest();
req.open(method, url, false);
req.send(payload);
action();
}
else if (window.ActiveXObject)
{
req = new ActiveXObject("Microsoft.XMLHTTP");
if (req)
{
req.onreadystatechange = action;
req.open(method, url, false);
req.send(payload);
}
else
{
alert("Could not create ActiveXObject(Microsoft.XMLHTTP)");
}
}
}
... and here is a typical action ...
function insertHtml(target)
{
var pageTarget = arguments[0];
if (req.readyState == 4) // 4 == "loaded"
{
if (req.status == 200) // 200 == "Ok"
{
if (req.responseText.indexOf("error") >= 0)
{
alert("Please report the following error...");
pretty = req.responseText.substring(req.responseText.indexOf("error"),1200);
pretty = pretty.substring(0,pretty.indexOf("\""));
alert(pretty + "\n\n" + req.responseText.substring(0,1200));
}
else
{
div = document.getElementById(pageTarget);
div.innerHTML = req.responseText;
dimOff();
}
}
else
{
alert("Could not retreive URL:\n" + req.statusText);
}
}
}