3

Some kinde of pseudo-synchronous question once again...

I'm looking for the best practice to run a function, after the completition of all ajax requests inside a loop.

Bad example:

var files = ["file1","file2","File3"];
var success = [];
var error = [];

for (var i = 0; i < files.length; i++) {
    $.ajax({
        type: "HEAD",
        url: files[i]
        }).done(function(){
            console.log("file found");
            success.push(files[i]);
            doThisWhenAllFilesChecked();
        }).fail(function () {
            console.log("file not found");
            error.push(files[i]);
            doThisWhenAllFilesChecked();
        })
}

Bad example 2: synchronous, just to illustrate what i'm looking for:

var files = ["file1","file2","File3"];
var success = [];
var error = [];

for (var i = 0; i < files.length; i++) {
    $.ajax({
        type: "HEAD",
        async: false, // <-- !
        url: files[i]
        }).done(function(){
            console.log("file found");
            success.push(files[i]);
        }).fail(function () {
            console.log("file not found");
            error.push(files[i]);
        })
}
doThisWhenAllFilesChecked();
Elvis
  • 289
  • 4
  • 14
  • 1
    try jquery $.when(), it will call the success and error callback once all the ajax request are finished. Check the jquery documentation for more details – atul Jul 29 '16 at 07:13
  • Thanks! "$.when()" looks promising, but could not figure out yet, how to use it in my case, since "fail()", "done()" or "then()" are no options to fire a function after the loop regardless of their succes or error handling. I also found this answer, which i'm currently looking at: http://stackoverflow.com/a/18425082/1536850 – Elvis Jul 29 '16 at 09:01

3 Answers3

1

you can do this-

 var files = ["file1","file2","File3"];
    var success = [];
    var error = [];
    var k = 0;
    for (var i = 0; i < files.length; i++) {
        $.ajax({
            type: "HEAD",
            url: files[i]
            }).done(function(){
                console.log("file found");
                 k++;
                success.push(files[i]);
                doThisWhenAllFilesChecked();
            }).fail(function () {
                 k++;
                console.log("file not found");
                error.push(files[i]);
               doThisWhenAllFilesChecked();
            })
    }

    function doThisWhenAllFilesChecked(){
      if(k==files.length){
        k = 0;
        //execute code here
      }
    }
Elvis
  • 289
  • 4
  • 14
Gaurav Srivastava
  • 3,232
  • 3
  • 16
  • 36
  • 1
    Thanks! Looks good and easy! :-) I thought about using a "while"-loop in a similar way; i'm just not sure, if this is best practice...?! – Elvis Jul 29 '16 at 09:05
  • 1
    i think using this code will not affect performance issues because its just using and if condition to check if the further code should be executed. – Gaurav Srivastava Jul 29 '16 at 09:41
  • 1
    I marked this as the soulution, since it does what i've been looking for and is clean and easy to use. Thanks! – Elvis Jul 29 '16 at 10:22
0

You need to chain all the promises together, so something like:

var promiseArray = []
for (var i = 0; i < files.length; i++) {
    //ajax returns a promise so capture this.
     promiseArray.push($.ajax({
        type: "HEAD",
        url: files[i]
        }).done(function(){
            console.log("file found");
            success.push(files[i]);
        }).fail(function () {
            console.log("file not found");
            error.push(files[i]);
        })
   );
}

//when can accept an array of deffered objects just call then() after these all return
$.when(promiseArray).done(doThisWhenAllFilesChecked());

In the case where multiple Deferred objects are passed to jQuery.when(), the method returns the Promise from a new "master" Deferred object that tracks the aggregate state of all the Deferreds it has been passed. The method will resolve its master Deferred as soon as all the Deferreds resolve, or reject the master Deferred as soon as one of the Deferreds is rejected.

Note that doThisWhenAllFilesChecked() will run async also

Liam
  • 27,717
  • 28
  • 128
  • 190
  • I've been messing around with this answer (http://stackoverflow.com/a/18425082/1536850), which looks like a similar approach, but the "then()"-event fires on each success and does not wait for all requests to be completed. – Elvis Jul 29 '16 at 09:53
  • You may need to return a new promise, possibly from a always() inside your ajax call, it'll need a bit of playing around with to get everything to dovetail exactly – Liam Jul 29 '16 at 10:00
0

Try something like this. Note this just pseudo code

var files = ["file1","file2","File3"];
var success = [];
var error = [];
var promisese = [];
function xhrCall(fileName){
   return $.ajax({
        type: "HEAD",        
        url: fileName
        });
}
function errorCallback(){
 // do something
}
for (var i = 0; i < files.length; i++) {
    promisese.push(xhrCall(files[i]));
}
$.when(promisese).then(doThisWhenAllFilesChecked, errorCallback);
Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
atul
  • 552
  • 4
  • 16