0

The idea is to make AJAX request wait for the controller reply before continuing execution. This is because I implemented AJAX inside a for loop.

for (var i = 0; i <= qtg.length-1; i++) {
    index++;
    gq(type, objParams.intro + " #" + index, qtg[i]); // ajax request happens here
}

function gq(type, intro, qtg) {
    var new_question_params = "type=" + type+ "&intro=" + intro+ "&q=" + qtg;

    $.ajax({
        type: "POST",
        async: false, // async set to false doesnt do a thing
        url: "./cntlr/generate/",
        data: new_question_params,
        success: function(data, textStatus, jqXHR) {
             console.log("created order : " + (data.q.order));
        },
        dataType: "json"
    });
}

expected output should be:

created order : 1

created order : 2

created order : 3

created order : 4

Ajax returns:

created order : 4

created order : 2

created order : 1

created order : 3

any ideas?

Community
  • 1
  • 1
Hard Spocker
  • 765
  • 11
  • 32

5 Answers5

4

Answer

While async might wait for the AJAX execution, your code inside the loop is still making all 4 call at the same time.


Suggestion

Not sure why you're doing the loop, but this is a great place to make AJAX callbacks, like this:

var totalNumber = qtg.length;

function gq(type, intro, i) {
    var new_question_params = "type=" + type+ "&intro=" + intro+ "&q=" + qtg[i];

    $.ajax({
        type: "POST",
        async: false, // async set to false doesnt do a thing
        url: "./cntlr/generate/",
        data: new_question_params,
        success: function(data, textStatus, jqXHR) {
             console.log("created order : " + (data.q.order));
             if (i < totalNumber) 
                 gq(type, intro, i+1);
        },
        dataType: "json"
    });
}
Shomz
  • 37,421
  • 4
  • 57
  • 85
  • im trying to create multiple questions, thus using for loop to generate it. is there anyway not to use for loop? :) @Shomz – Hard Spocker Mar 09 '16 at 02:44
  • 1
    I see, I still suggest the callbacks because the for loop will fire all at the same time, there's no way for it to wait for an async request. Or you can do it with [promises](http://stackoverflow.com/questions/24660096/correct-way-to-write-loops-for-promise). – Shomz Mar 09 '16 at 02:46
  • Try `async`. Seems complex, but once you learn it you will find yourself doing all kinds of controls on asynchronous code. Your loop can be emulated with the `whilst` method. Not sure why my answer got a downvote. – noderman Mar 09 '16 at 02:46
  • I'm reading your answer @noderman. It seems powerful but too complex for this situation. The one who devote you didn't leave a comment why. – Hard Spocker Mar 09 '16 at 02:48
  • @noderman, please don't spam and repeat your answer as a comment here. See this about answering simple questions by suggesting heavy libraries: http://meta.stackexchange.com/questions/45176/when-is-use-jquery-not-a-valid-answer-to-a-javascript-question – Shomz Mar 09 '16 at 02:50
  • Just curious: is the if statement inside the success method really checking if an array is less than a number? I haven't seen that code before that's why I was wondering if that was possible. – Nathan Mar 09 '16 at 03:06
  • 2
    @Nathan, it was actually a typo as I was changing function parameters and forgot to update that one. Thanks for reporting it. – Shomz Mar 09 '16 at 05:03
1

You could use .queue() to return results in sequential order

function gq(type, intro, key) {
    var new_question_params = "type=" + type+ "&intro=" + intro+ "&q=" + key;    
    // included `return` statement, to return jQuery promise object from `gq` call
    return $.ajax({
        type: "POST",
        // async: false, 
        // async set to false doesnt do a thing
        url: "./cntlr/generate/",
        data: new_question_params,
        // substituted `.then()` for `success`
        dataType: "json"
    });
}

$({}).queue("q", $.map(qtg, function(request, key) {
  return function(next) {
    ++index;
    gq(type, objParams.intro + " #" + index, request)
   .then(function(data, textStatus, jqXHR) {
     console.log("created order : " + (data.q.order));
   })
   .then(next);
  }
})).dequeue("q")

var qtg = [1, 2, 3, 4], index = 0;

function asyncFn(request, index) {
  return $.Deferred(function(dfd) {
    setTimeout(function() {
      dfd.resolve(["request: " + request, "index: " + index])
    }, Math.random() * 3000)
  })
}

$({}).queue("q", $.map(qtg, function(request, key) {
  return function(next) {
    ++index;
    return asyncFn(request, index)
      .then(function(data) {
        console.log(data);
      }).then(next)
  }

})).dequeue("q")
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
guest271314
  • 1
  • 15
  • 104
  • 177
1

Or you can do some old callback-style recursion:

(basic example without error handling - your question had no error handling too so I suppose that is a part of design?)

function gq(type, intro, qtg, callbackOnSuccess ) {
    var new_question_params = "type=" + type+ "&intro=" + intro+ "&q=" + qtg;

    $.ajax({
        type: "POST",
        url: "./cntlr/generate/",
        async: false,
        data: new_question_params,
        success: function(data, textStatus, jqXHR) {
            console.log("created order : " + (data.q.order));
            callbackOnSuccess();
        },
        dataType: "json"
    });
}

function curryAjax( a_qtg, callbackOnTermination ) {

    if (
        ( typeof a_qtg == 'undefined' ) ||
        ( a_qtg.length <= 0 )
    ) {
        callbackOnTermination();
        return;
    }

    var car = a_qtg.shift();
    var cdr = a_qtg;
    gq(
        type,
        objParams.intro + " #" + index,
        car,
        function() {
            curryAjax(cdr, callbackOnTermination);
        }
    );
}

curryAjax( qtg, function(){ console.log('Recursion (serial sequence) complete.'); } );

Callback syntax is referred by many JS-programmers as inferior to Promise-style controls but it has at least one advantage over Promises - Promises as interesting as they are - is a new field of knowledge, a new standard and way of thinking to wrap your head around. And they are no silver bullet - there were cases in my life when they were not expressive enough for some buisness-logic. Callbacks are wierd but fun. In small quantities they are tasty and maintainable. Recursions - too ^_^

Jaiden Snow
  • 852
  • 5
  • 5
0

You could use the excellent and powerful async library

https://github.com/caolan/async

it does not make it synchronous -- and you shouldn't, but allows you to control the flow. For example, using series

async.series([
    function(callback){
        // do some stuff ...
        callback(null, 'one');
    },
    function(callback){
        // do some more stuff ...
        callback(null, 'two');
    }
],
// optional callback
function(err, results){
    // results is now equal to ['one', 'two']
});

Update

In your case, you could emulate the loop by using whilst

async.whilst(
    function () { return count < 5; },
    function (callback) {
        count++;
        setTimeout(function () {
            callback(null, count);
        }, 1000);
    },
    function (err, n) {
        // 5 seconds have passed, n = 5
    }
);
noderman
  • 1,934
  • 1
  • 20
  • 36
0

found the following thing in w3 schools

xhttp.open("GET", "ajax_info.txt", false);

scroll down to the part where it says ASYNC=FALSE w3 school

Samarth S
  • 313
  • 4
  • 5