0

This seems like a ridiculously trivial issue but I can't solve it.

I have this function. var q is assigned to an array of strings. alert(q) successfully prints the entire array when the function is called.

function initQuestions() {
    $.post("quiz.php", { 'func': 'load' }, function(data) {
        var q = data.split(".\n");
        alert(q);
        return q;
    });
}

However, when I attempt to use the function (as depicted below in 2 ways) I am told the array is undefined. Why is this the case?

var questions;

$(function() {
    //This doesn't work
    questions = initQuestions();
    alert(questions);

    //Neither does this
    alert(initQuestions());
});

Upon further research I added a callback to initQuestions() but am having the same result.

hakre
  • 193,403
  • 52
  • 435
  • 836
FuriousD
  • 844
  • 5
  • 16

3 Answers3

3

The post call is asynchronous: Async Javascript

Basically, the initQuestions() function returns null before the post finishes

Thinks of it like this:

function initQuestions() {
    $.post("quiz.php", { 'func': 'load' }, function(data) {
        var q = data.split(".\n");
        alert(q);
        return q; // <- returns to the caller of function(data), not initQuestions()!
    });
    return null; // <- This happens before function(data) is complete
}

To make it work as expected, you need to supply a callback for when the post is successful and finishes.

function initQuestions(callback) {
    $.post("quiz.php", { 'func': 'load' }, function(data) {
        var q = data.split(".\n");
        alert(q);
        callback(q);
    });
}

var questions;

function doSomthingWithQuestions() {
    alert(questions); // <- should work
    // do the things with the questions
}

$(function() {
    initQuestions(function(result) {
       questions = result;
       doSomethingWithQuestions();
    });

    // Don't use `questions` here as the callback hasn't fired yet. 
});
Community
  • 1
  • 1
Josh B
  • 1,748
  • 16
  • 19
  • This explains why it doesn't work, but not what the OP should do about it. – jfriend00 Sep 10 '13 at 06:12
  • Thanks, this worked, but it''s something I tried previously to no avail. What made it work this time round was placing the function call at the very top of document.ready. Why does it happen that a piece of code won't work when placed after an unrelated piece of other code? – FuriousD Sep 10 '13 at 06:32
  • Actually I spoke too soon. `questions` is still undefined outside of the callback – FuriousD Sep 10 '13 at 06:35
  • It will be if you're calling code outside of the callback before the callback has fired. If you want to use the questions variable, you have to use it *after* the questions are loaded – Josh B Sep 10 '13 at 06:40
0

The post is asynchronous, return doesnt go to the function you expect, but to the success handler:

function initQuestions() {
  $.post("quiz.php", { 'func': 'load' }, function(data) { // <- this function has that return
    var q = data.split(".\n");
    alert(q);
    return q;
  });
}

here is how to supress asynchronous behaviour and achive what you want

EDIT:

As some people said here, asych = false is a bad idea since it freezes you JS code until the request is done (can take seconds with slow connection), so solution would be to do whatever you want in the success function:

questions = initQuestions(); //wrong
fillDivsWithData(questions); //use callback instead:

function initQuestions() {
  $.post("quiz.php", { 'func': 'load' }, function(data) {
    var q = data.split(".\n");
    console.log(q); //diplay this in you browser's JS console
    fillDivsWithData(q);
  });
}

result is same, but thanks to asynch request your JS code doesnt freeze for seconds if you have potatoe internet connection.

Community
  • 1
  • 1
kajacx
  • 12,361
  • 5
  • 43
  • 70
  • http://stackoverflow.com/questions/6685249/jquery-performing-synchronous-ajax-requests maybe even better example (duplicate in fact) – kajacx Sep 10 '13 at 05:53
0
var questions; // undefined right now
initQuestions(function(_questions){
  questions = _questions; // the value has been set thanks to the anonymous function you passed as the callback
})

function initQuestions(callback  // this is a callback function reference) {

  // This HTTP Post call takes time to complete and is done asynchronously
  $.post("quiz.php", { 'func': 'load' }, function(data) {
    var q = data.split(".\n");
    // Luckily your initQuestions now takes in a callback function
    // You have access to the callback function here and when ready you can use it
    callback(q);
  });
  // JavaScript engine doesn't wait for your HTTP call to complete 
  // and will continue to execute the function
  // In this case, your function isn't returning anything hence undefined

}
cbayram
  • 2,259
  • 11
  • 9
  • asynch = false, that solves this problem, this solution is needlessly complicated – kajacx Sep 10 '13 at 06:07
  • This indicates that asynch = false shouldn't be used http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call – FuriousD Sep 10 '13 at 06:10
  • @kajacx - async false is `bad` for the user experience and a bad, bad design decision (it locks up the browser UI during the ajax call). It should pretty much never be used. – jfriend00 Sep 10 '13 at 06:11
  • Yea, that lock up is bad, but OP asked how his initQuestions() function can return data from ajax, and that cant be done otherwise then by asynch=false – kajacx Sep 10 '13 at 06:16
  • "Why is this the case?" was the question. – cbayram Sep 10 '13 at 06:19