0

I am relatively a newbie to jquery and ajax and am trying to use the concept of deferrals and promises to solve this problem I have. I would like to do the following: Call a list of URLS and process the result returned from the urls. I would like to first process the results in parallel, and then combine the processed results to give me a final result.

Th pseudo-code is as follows:

var deferredAjaxCalls = [];
for (var i = 0; i < jobsListLength; i++) {
    deferredAjaxCalls.push(
        $.ajax({
            url:"/myurl",
            method:"POST",
            contentType:"application/json",
            dataType:"json",
            data:mydata,
            success:function(result){
              //Some code here that is performance intensive
            } 
        });
}
$.when.apply(this,deferredAjaxCalls).done(function(){
    for (var k=0; k< arguments.length;k++){
            //combine the results of the individual results of the
            // success part of all the ajax calls and execute some more 
            //code synchronously
    } 
}).fail( function (jqXHR, status, error) {
   //Log failed status
 });

Initially, I moved all of the code from the success part inside the $.when.apply().However, this resulted in very slow performance as there is a lot of intensive computation that is now executed synchronously. So I am looking for a way to execute part of the code independently, and the final piece synchronously

I did read about using promises, but could not find any example where promises are used with an array of ajax calls with intermediate processing before finally synchronising in the when.apply() block

What would be a good way to solve this problem?

Thanks!

Neo_one
  • 1
  • 1

2 Answers2

0

Starting with an array jobsList, you probably want something like this :

var deferredAjaxCalls = jobsList.map(function(job) {
    return $.ajax({
        url: "/myurl",
        method: "POST",
        contentType: "application/json",
        dataType: "json",
        data: mydata
    }).then(process);// where `process` is a function that accepts $.ajax's (data, textStatus, jqXHR) and returns a *single* value/object - the result of the processing. This will standardise the data delivered below by $.when() to its success handler.
});
$.when.apply(null, deferredAjaxCalls).then(function() {
    // Due to `.then(process)` above, `arguments` are guaranteed to comprise one arg per ajax call.
    // Otherwise you potentially have the problem reported here - http://stackoverflow.com/questions/12050160/
    for (var k=0; k<arguments.length; k++) {
        // Combine the results of the individual results of the success part of all the ajax calls and execute some more code synchronously.
    }
    // In this function deliver an error by returning `$.Deferred().reject(new Error('myReason'))`
    return combined_result;
}, function(jqXHR, status, error) {
    // This hander will receive multiple $.ajax() params, which are best normalised into a single Error object. 
    return new Error(status); // similar to .then(process) above, reduce $.ajax's error args to a single "reason".
}).then(null, function(err) {
    // All errors delivered by code above arrive here as a js Error.
    // But please note that, in jQuery <v3.0, any uncaught errors above will genuinely throw (to the console).
    console.log(err.message);
});
Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
-1

You can try using deferreds:

  var req_responses = [];
  var deferreds = [];

  for(var i in jobs) {
     deferreds[i] = new $.Deferred();
  }

  for(var i in jobs) {
     (function(i) {
        $.ajax ({
           url: ".",
           type: "POST",
           dataType: "json",
           done: function(response) {
              //process the response
              req_responses[i] = response;
              deferreds[i].resolve();
           }
        });
     })(i);   
  }

  $.when.apply(deferreds).then(function(os) {
     //all the responses are in req_responses
     //finish processing
     alert("done");
  });
Dane Iracleous
  • 1,659
  • 2
  • 16
  • 35
  • 1
    Please no! Resolving a deferred (or promise) with the result delivered by an async process that already returns a promise is known as the [explicit promise construction antipattern](http://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it) and should be avoided. Whereas `$.ajax()` has a `success:` option, it also returns a promise, which can itself be returned and/or be used as the leading element of a promise chain. – Roamer-1888 Nov 18 '15 at 19:29
  • Interesting. So the solution is to just use the done callback instead of success? – Dane Iracleous Nov 18 '15 at 20:45
  • Dane, more likely `.then()`, which will allow a processed result to be returned for delivery down the promise chain (into $.when(...).then()'s handler in this case). – Roamer-1888 Nov 18 '15 at 20:53