Reputation: 226
I've looked all over the place and none of the answers I've found have been able to help me out with this problem. Basically I have a function that calls a separate function to make an XMLHttpRequest
. The request goes to a server, which generates a random number and returns it to the page.
The problem is that while the request is fetching the data, the caller function continues through its commands. I need to have the data from the request before the caller can move forward. People have mentioned callbacks and promises, neither of which I have been able to grasp with what's available online. I'd rather use callbacks because promises aren't supported in all browsers. Can someone please help walk me through how to use them? I can provide some of the code that I have if needed.
Here's my caller function:
function plotData(dataSet)
{
var x = xScale+20; // 20 = margin length
var y = 260; //origin of graph
getRequest();
console.log("x = "+x);
console.log("dataSet = "+dataSet[0]+", "+dataSet[1]);
... //rest of the function commands
}
Here's my XML 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", "lak1010_hw05.php", true);
request.send();
}
Upvotes: 0
Views: 659
Reputation: 1951
Promises are the way to go here. You can use a Promise polyfill to help take care of unsupported browsers.
var myPromise = (function() {
return new Promise(function(resolve, reject) {
$.ajax({
url:'/page.php?id=123',
type:'POST',
success: function(data) {
resolve(data);
}
});
});
})();
myPromise.then(function(data) {
// Continue code here
});
Basically you create a promise that gets resolved with the data returned from your AJAX call. myPromise.then()
gets fired when the Promise is resolved and you continue your code execution there with the data you passed along in the promise resolution. You can also reject()
a promise if the AJAX error'd or had invalid data etc.
With your code something like this:
function plotData(dataSet)
{
var x = xScale+20; // 20 = margin length
var y = 260; //origin of graph
var myPromise = new Promise(function(resolve, reject) {
$.ajax({
url:'/page.php?id=123',
type:'POST',
success: function(dataSet) {
resolve(dataSet);
}
});
});
myPromise.then(function(dataSet) {
console.log("x = "+x);
console.log("dataSet = "+dataSet[0]+", "+dataSet[1]);
... //rest of the function commands
});
}
Simpler with just the callback:
function plotData(dataSet)
{
var x = xScale+20; // 20 = margin length
var y = 260; //origin of graph
$.ajax({
url:'/page.php?id=123',
type:'POST',
success: function(dataSet) {
console.log("x = "+x);
console.log("dataSet = "+dataSet[0]+", "+dataSet[1]);
... //rest of the function commands
}
});
}
Upvotes: 1
Reputation: 12022
Here is your modified getRequest
function with the callback,
function getRequest(callback)
{
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]);
// here call your callback
callback(random);
}
else
{
alert ('There was a problem with the request');
}
}
}
request.open("GET", "lak1010_hw05.php", true);
request.send();
}
Your calling method,
function plotData(dataSet)
{
var x = xScale+20; // 20 = margin length
var y = 260; //origin of graph
getRequest(function(random){
console.log('Random number received:');
console.log(random);
});
console.log("x = "+x);
console.log("dataSet = "+dataSet[0]+", "+dataSet[1]);
... //rest of the function commands
}
Upvotes: 1
Reputation: 100200
Try the new fetch API. Promises with jQuery are pretty broken :/
=> https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
var myHeaders = new Headers();
var myInit = { method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default' };
fetch('flowers.jpg', myInit)
.then(function(response) {
return response.blob();
})
.then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
});
Upvotes: 1
Reputation: 634
EDIT: Well shit I missed your edit and thought it was just a general promise question.
This is a function with parameters:
test = function(parameter) {
if (paramater) {
return true
} else {
return false
}
}
This is a function that has an extra parameter called a 'callback'.
test = function(parameter, callback) {
if (parameter) {
callback(null, 'result')
} else {
callback('error')
}
}
A callback usually has two arguments. An error, and an optional result.
As you can see, if parameter is true, we run a function that returns 'null' as the error, and 'result' as the result.
If you'd like to delay functions using a callback, you simply call the function like this:
test(true, function(err, result) {
if(err) {
console.log(err)
} else {
console.log(result)
}
})
Replace console.log with the function you want upon a successful result or error. It's hard to understand at first, but try writing some code for it - the reading is usually useless when you don't have an ingrained idea of asynchronous code.
You have to manually add the callbacks and stuff - here's an extract from my backend.
this.findOneByPhone = function(phone, req, res, callback) {
connection.acquire(function(err, con) {
con.query('select * from users where phone = ?', [phone], function(err, result) {
con.release()
if (err) {
callback(err)
} else {
callback(null, JSON.stringify(result[0], null, 4))
}
})
})
}
And then calling it;
this.findOneByPhone(user.phone, null, null, function(err, foundUser) {
if (err) {
res.status(500).json({message: 'Signup findOneByPhone failed.', error: err})
} else {
if (foundUser) {
var foundUserJSON = JSON.parse(foundUser)
res.json({status: 0, message: 'User already found in database, please skip signup', result: 'skip'})
} else {
res.json({status: 0, message: 'User is not in database, please signup', result: 'signup'})
}
}
})
Upvotes: 1