-1

I have a for loop, and in one iteration (of something) I need to make four AJAX requests, then wait until result from the last request.

Now I've got only how to pass data from previous promise to another, like in this cool answer, but I need to return the value from the last AJAX call to the outer array (and wait until the last AJAX call is done) and then continue other functions out of the loop.

                attaches.forEach(function(attach)) {
                    if(attach.val == "val1"){
                        attachments.push(attach.val1);
                    }
                    if(attach.val == "val2"){
                         attachments.push(attach.val2);
                    }
                    if(attach.val == val3){
                       function func1(){
                           var params = [param1,param2];
                           return   $.post(api, params.join('&'))
                       }
                       function func2(){
                           console.log('1111');
                           return new Promise(function(resolve, reject)) {
                               var xhr = new XMLHttpRequest();
                               xhr.onload = function () {
                                   resolve(xhr.response);
                               } 
                               xhr.open('GET', img_src);
                               xhr.responseType = 'blob';
                               xhr.send();                           
                           });
                       }
                       function uploadPhoto(upload_url, bulbSend){
                               console.log('<Del><F7>              function uploadPhoto');
                           return $.ajax({
                               url: upload_url, 
                               type: 'POST',
                               data: bulbSend,
                               dataType: 'json',
                               processData: false,
                               contentType: false,
                           });                   
                       } 
                       function saveResult(params){
                          
                           return $.post(api, params.join('&'))
                       }
                           func1().then(fun1hand()).then(console.log('a32w436bya3b7naua'));
                       function fun1hand(){
                           return function(dat4a) {
                               return  func2().then(func2hand(dat4a));
                           };
                       }
                       function func2hand(dat4a){
                           console.log('2222');
                           return function(datums){
                               console.log('3333');
                               var upload_url = dat4a.upload_url;
                               console.log('UPLOAD__URL BEFORE PROMISE  '+upload_url);
                               var bulbSend = new FormData();
                               bulbSend.append('file1', datums, 'file.jpg');
                               
                 return uploadPhoto(upload_url,bulbSend).then(func3hand());
                           }
                       }
                       function func3hand(){
                         return  function(data2){
                             var params = [data2.param1, data2.param2, data2.param3];
                             return saveResult(params).then(pushToAttachmentsHandler());
                         }
                       }
                       function pushToAttachmentsHandler(){
                           return function(data3){
                               console.log('PUSUSUSUSSUSUSUUSUS PUSHHHHHHH PUSH DA BAUTTON');
                               console.log(attachments);
                               return pushDat(data3).then(console.log(attachments));
                           }
                       }
                       function pushDat(data3){
                           console.log('1111');
                           return new Promise(function(resolve, reject) {
attachments.push(data3.param3+"_"+data3.param1));
                           console.log('11111111111');
                           });
                       }
                        
                    }
                });

Functions that are out of loop start their console.logs before console.log('3333') inside promises... but they need await until AJAX calls inside the loop are done and loop is completed.

And now I need to repeat AJAX after timeout if it was rejected (server requests limit per second) - how could I set it in my code for native XMLHttpRequest() that is inside of promise, and for jQuery AJAX calls that are returned?

freginold
  • 3,946
  • 3
  • 13
  • 28
Whats Myname
  • 41
  • 1
  • 9

2 Answers2

0

Callbacks or promises are capable of handling that kind of async control flow...

Assuming your original non working code is...

for(var i=0; i < 10; i++){
    $.get('http://example.com/rest/users/'+i);
    $.get('http://example.com/rest/posts/'+i);
    $.get('http://example.com/rest/comments/'+i);
    $.get('http://example.com/rest/events/'+i);
}

Callbacks...

var i = 1;

getSet(repeater);

// define a repeater function to be used as recursive callback
function repeater (){
    // increment counter
    i++;
    // if we still have items to process, get another set
    if(i < 10){
        getSet(repeater);
    }
}

function getSet(cb){
    // define queue
    var counter = 0;
    // make four api calls, defining success callbacks, which call the
    // originally passed callback if the counter reaches 0. Increment counter before each request. This means the callback fires only for the last result
    counter++;
    $.get('http://example.com/rest/users/'+i, handleSuccess);
    counter++;
    $.get('http://example.com/rest/posts/'+i, handleSuccess);
    counter++;
    $.get('http://example.com/rest/comments/'+i, handleSuccess);
    counter++;
    $.get('http://example.com/rest/events/'+i, handleSuccess);

    function handleSuccess(data){
        // do something with data
        --counter || cb();
    }
}

This pattern works something like this...

getSet is called the first time, with a repeater function that is expected to be called once all async requests are done. The getSet function increments a stack when making async calls, and decrements in the async callbacks, calling the repeater when the stack settles back to zero and there are no more async jobs in the queue. The repeater callback then repeats the whole process, calling getSet and passing itself as the callback until a condition is met.

Billy Moon
  • 57,113
  • 24
  • 136
  • 237
  • why doesn't cb(); run inside first async callback ? does meaning of 'or' operator in last ajax call differ of it in first? and i need to wait for data from prev ajax to call next... i need ajax chain only if something appears in loop, if iteration has thing, that don't require ajax > it simply pushs data in outer array... i think that i dont understand concept of your great answer – Whats Myname Mar 20 '16 at 01:25
  • ok, so if problem you are having is that code is sometimes async, and sometimes sync - then just code it as if it was async all the time, and when you need to `simply push` just trigger callback with data immediately instead of in ajax callback. Does that help? – Billy Moon Mar 20 '16 at 01:40
  • i need values from previous ajax requests in following ajaxes something like this ( $.get('http://example.com/+i', function(data1){ --counter || cb(); }); $.get('http://example.com/+data1.something', function(data2){ ... do something with data 1 and data2.... --counter || cb(); }); and share it throught for last ... i need to waint for request from first before next . but now i dont understand --counter || cb(); statement ... shall requests in your example wait until prev? and why var i = 1; – Whats Myname Mar 20 '16 at 03:18
  • I'v got something about it here [link](http://stackoverflow.com/questions/4368946/jquery-callback-for-multiple-ajax-calls) , [link](http://stackoverflow.com/questions/14031421/how-to-make-code-wait-while-calling-asynchronous-calls-like-ajax),[link](http://stackoverflow.com/questions/17462397/increment-and-decrement-variable-until-statement-is-true), but why is cb(); not executed when counter decremented at first time? becouse counter it first time == 0...? will your code provide waiting request from first ajax before next? sorry for my stupid questions – Whats Myname Mar 20 '16 at 07:12
  • The ajax success callbacks happen much later than the surrounding code. They only get executed after the ajax request is satisfied successfully. The counter is incremented four times before any success callback decrements it. I updated answer to hopefully make this clearer to you – Billy Moon Mar 20 '16 at 11:19
-1

It looks simple, for both async and sync ajax requests you may use:

var myVar;

yourLoop(function() {
    yourAjax(function(result) {
        myVar = result;
    });
});

Change your variable value on ajax success(finish) callback

UPD:

If you need a callback on the last result I may suggest you this hackly option:

var myVar, timeout;

yourLoop(function() {
    yourAjax(function(result) {
        myVar = result;

        clearTimeout(timeout);
        timeout = setTimeout(function() {
            // do something . . .
            console.log('last result', myVar);
        }, 1000);
    });
});

Note: change 1000 to expected maximum response time

Undefitied
  • 747
  • 5
  • 14