4

Let's say I have an array of ajax calls like so:

// an array of ajax calls
var callsArray = [];
callsArray.push(
  $.ajax({
    url: '/url1';
    cache: false,
    dataType: 'html'
  }),
  $.ajax({
    url: '/url2';
    cache: false,
    dataType: 'html'
  })
)

I know in advance that at least one of these two calls will fail. I want to execute a function after BOTH calls have resolved as either succeeded or failed, and I also want to log any failures.

This won't work:

// NOT APPROPRIATE
var errors = '';
$.when.apply(null, callsArray)
  .done(function() {
     console.log('Both calls completed but these urls failed: ' + errors);
  })
  .fail(function() {
     errors += this.url + ' ';
  })

The problem with the above is that .fail executes if even one call fails, while .done only executes if zero calls fail. Also I can't use .always because it executes as soon as any call resolves.

Therefore I'm looking for something like this:

// FANTASY CODE
var errors = '';
$.when.apply(null, callsArray)
  .allCallsResolved(function() {
     // this executes only when all calls have
     // returned either a success or a failure
     // rather than when all calls succeed
     console.log('All calls completed but these urls failed: ' + errors);
  })
  .everyFailure(function() {
     // this executes every time a call fails
     // rather than as soon as any call fails 
     errors += this.url + ' ';
  })
mattthew
  • 528
  • 4
  • 11

3 Answers3

1

You could wrap each ajax call in a Promise that resolves on both success and failure and then use Promise.all to verify that all calls are done and/or failed:

const promises = callsArray.map(function(call) {
    return new Promise(function(resolve, reject) {
        call.done(resolve).fail(function(error) {
            console.log(error);
            resolve(error);
        });
    });
});

Promise.all(promises).then(function(values) {
     console.log(values);
     //all calls done or failed
});
FuzzyTree
  • 32,014
  • 3
  • 54
  • 85
  • @Adyson has pointed out that my question is a [duplicate](https://stackoverflow.com/questions/5824615/jquery-when-callback-for-when-all-deferreds-are-no-longer-unresolved-either), therefore I will mark this question as such. However, your solution is good and different from the one offered in the other question. – mattthew Oct 16 '17 at 07:38
0

var callsArray = [];
callsArray.push(
  $.ajax({
    url: 'https://httpbin.org/status/404',
    cache: false,
    dataType: 'html'
  }),
  $.ajax({
    url: 'https://httpbin.org/status/200',
    cache: false,
    dataType: 'html'
  })
);

callsArray.forEach((e) => {
  e.done(() => console.log('done'))
    .fail(() => console.log('fail'))
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
davidchoo12
  • 1,261
  • 15
  • 26
-1

I did this long back using Deferred function in Jquery.

     var diff_array = [];
        var count=0;//you may use counter to know how many Deferred objects are resolved/rejected.

        //Iterate your callsArray 

        for(i in callsArray){

        diff_array[i] = $.Deferred();
        //execute each ajax
        //if ajax fails call reject else resolve/promise.
        diff_array[i].resolve();
        //count++ based on resolve/reject
        }

        //any where in the script
        // write deferred.done() which will be called immediately on resolving corresponding deferred object.
        diff_array[13].done(
        function() {
        .
        .
          if(count=callsArray.length){
           callFinalFunction();
           }
        }
        );