0

I need to get resource A followed by B, etc until n. I did this in the following way following the official guide https://github.com/kriskowal/q#sequences .

var chain = Q();
            for(var i=0;i<x.length;i++){
            chain = chain.then( $.ajax({
                        type: "POST",
                        url : data_url,
                        data:pdata
                }) );
return chain;   
HackToHell
  • 2,223
  • 5
  • 29
  • 44
  • Why would you use Q with jQuery `$.ajax`, there's no need for that as long as you're doing **asynchronous** requests. – adeneo Oct 12 '16 at 13:23
  • Check this answer, that might help you http://stackoverflow.com/a/39679275/6608101 – Mohit Tanwani Oct 12 '16 at 13:24
  • @adeneo Can't set async to false because this loads from a different origin, Loading.. lemme check it out. – HackToHell Oct 12 '16 at 13:27
  • You should ***NEVER*** set async to false, it should always be `true`, which is the default value, i.e. ***asynchronous*** requests. – adeneo Oct 12 '16 at 13:28
  • Yes, I was advised not to do that and look into promises, hence the library Q, but I can't seem to make it wait for the other one to complete. – HackToHell Oct 12 '16 at 13:30
  • jQuery's `$.ajax` already returns a "promise". – adeneo Oct 12 '16 at 13:32
  • @adeneo Aye, so my reasoning was, it chains multiplicity. Hence the `.then()` will not bee invoked until the AJAX is done. But doesn't seem to the case :/ I think I am missing something critical – HackToHell Oct 12 '16 at 13:36
  • It's not really clear to me what you're trying to do, but the pattern for a simple "waterfall" with async requests would be something like -> https://jsfiddle.net/adeneo/ac8xcsey/ – adeneo Oct 12 '16 at 13:39
  • @Bergi - While the dup you marked is technically a similar problem to here, it is not very clear that those answers show the OP how to solve this specific issue. I prefer to only mark a dup when at least one of the answers directly shows the OP how to solve their specific problem, not when the question is just in the same general tech area. – jfriend00 Oct 12 '16 at 18:54
  • @jfriend00 Yeah, I reopened. One day, we hopefully will have a canonical question for "don't pass promises as arguments to `then`" – Bergi Oct 12 '16 at 19:11
  • @adeneo That was exactly what I wanted to, thanks ! – HackToHell Oct 14 '16 at 08:57

1 Answers1

1

.then() handlers accept function references as arguments, not promises. Your code was executing your ajax calls immediately and then passing the returned promise to the .then() handler which is not valid.

If you want the Ajax calls to be executed later and in sequence, then you need to put them in a function like this so you can pass that function reference to .then(). In that way, the promise infrastructure can call your function some time in the future:

var chain = Q();
for (var i = 0; i < x.length; i++) {
    chain = chain.then(function(priorResults) {
        return $.ajax({
            type: "POST",
            url: data_url,
            data: pdata
        });
    });
}
return chain;

You pass a function reference to a .then() handler so the promise infrastructure can execute that function at some later time.

As you had it, the $.ajax() calls were all executed immediately and only the promises where chained.

If you are attempting to use the i variable inside the .then() handler, that will not work properly because the for loop will have finished and i will have its terminal value when the .then() handler is called. The usual solution is either to use let in ES6 for the for loop variable, iterate with something like .forEach() or to make sure the for loop contains a function/closure that can uniquely capture each separate value of the i variable. More details could be provided if you showed your actual code.


P.S. I presume there is some missing code in your question because you probably don't want to execute the exact same Ajax call each time.

If you are iterating an array, then a common design pattern for iterating an array serially using promises is with .reduce() like this:

array.reduce(function(p, item) {
    return p.then(function(priorResult) {
        return $.ajax(...);
    });
}, Q()).then(function(result) {
    // everything done here, final result
});
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • For the missing code, you might want to point out a probably [missing closure](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) as well :-) – Bergi Oct 12 '16 at 18:37
  • @Bergi - Some info in that regard added. – jfriend00 Oct 12 '16 at 18:51
  • Yep, there's some missing code that changes the data, enclosing it with the function made it work. Thanks :) – HackToHell Oct 14 '16 at 08:59