Luke Danger Kozorosky
Luke Danger Kozorosky

Reputation: 226

Making a Callback for AJAX Requests to return the response to the caller

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

Answers (4)

Ryan Tuosto
Ryan Tuosto

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

Aruna
Aruna

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

Alexander Mills
Alexander Mills

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

ARMATAV
ARMATAV

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

Related Questions