2

using Backbone.js we have an application, in which on a certain occasion we need to send an ajax post to a clients webservice.

however, the content to be posted, is dynamic, and is decided by a certain array.

for each item in the array we need to go fetch a piece of data.

after assembling the data that aggregated object needs to be sent.

as of now, i have a synchronous approach, though i feel that this is not the best way.

var arrParams = [{id: 1, processed: false},{id: 7, processed: false},{id: 4, processed: false}];

function callback(data) {
    $.post()... // jquery ajax to post the data... }

function fetchData(arr, data, callback) {
    var currentId = _(arr).find(function(p){ return p.processed === false; }).id;  // getting the ID of the first param that has processed on false...

    // ajax call fetching the results for that parameter.
    $.ajax({
        url: 'http://mysuperwebservice.com',
        type: 'GET',
        dataType: 'json',
        data: {id: currentId},

        success: function(serviceData) {
            data[currentId] = serviceData;  // insert it into the data
            _(arr).find(function(p){ return p.id === currentId; }).processed = true; // set this param in the array to 'being processed'.
            // if more params not processed, call this function again, else continue to callback
            if(_(arr).any(function(p){ return p.processed === false }))
            {
                 fetchData(arr, data, callback);
            }
            else
            {
                callback(data);
            }
        },
        error: function(){ /* not important fr now, ... */ }
    }); 
}

fetchData(arrParams, {}, callback);

isn't there a way to launch these calls asynchronous and execute the callback only when all results are in?

Sander
  • 13,301
  • 15
  • 72
  • 97

2 Answers2

8

You have to use JQuery $.Deferred object to sync them. Look at this article Deferred Docs

You can use in this way:

$.when(
   $.ajax({ url : 'url1' }),
   $.ajax({ url : 'url2' }) // or even more calls
).done(done_callback).fail(fail_callback);
Denis Ermolin
  • 5,530
  • 6
  • 27
  • 44
  • waw... I didn't know about this.. it is nice! – fguillen May 03 '12 at 10:03
  • does that work without ajax too? i can see situations where you go to a local database, where you are also in the situation that the function should wait on the separate database calls? though i have to say it is indeed a nice way of waiting for multiple ajax calls. – Sander May 03 '12 at 12:32
  • Sure it works, read the doc about deferreds. $.when takes any amount of $.deferred objects and when all of them calls .done/.fail invokes desired callback. – Denis Ermolin May 03 '12 at 12:39
  • @Denis, when will be the done_callback called? When it STARTED all the ajax requests, or when they all will be FINISHED (I suppoese they're async)? – Gavriel May 03 '12 at 13:06
  • done - when all callbacks successed(finished). IF you want to call callback no matter failed or successed ajax then use .then() – Denis Ermolin May 03 '12 at 13:09
0

I would do something like this:

make a function that besides the parameters that you pass to fetchData also gets the index within arrParams, then in a loop call that function for every element. In the success function set processed in your element to true, and check if "you're the last" by going through the array and see if all the rest is true as well.

A bit of optimization can be if you make a counter:

var todo = arrParams.length;

and in the success you do:

if (--todo == 0) {
   callback(...)
}
Gavriel
  • 18,880
  • 12
  • 68
  • 105