views:

264

answers:

5

Hi!

Imagine we have to sources to be requested by ajax. I want to perform some actions when all callbacks are triggered. How this can be done besides this approach:

(function($){
  var sources = ['http://source1.com', 'http://source2.com'],
  guard = 0, 
  someHandler = function() { 
    if (guard != sources.length) { return; }
    //do some actions
  };

  for (var idx in sources) {
    $.getJSON(sources[idx], function(){ guard++; someHandler(); })
  }
})(jQuery)

What I don't like here is that in this case I can't handle response failing (eg. I can't set timeout for response to come) and overall approach (I suppose there should be a way to use more power of functional programming here)

Any ideas?

Regards!

UPD: Thanks for solution with chaining callbacks. I found a good approach here:. this is what was proposed in comments:

(function hidenext(jq){
    jq.eq(0).fadeOut("fast", function(){
        (jq=jq.slice(1)).length && hidenext(jq);
    });
})($('div#bodyContent a'))

With a little bit of tweaking it can wait for the last callback.

Now I want to handle properly long running requests. Any clues?

A: 

You can always use $.ajax with "async: false" in options and/or use proper callbacks (beforeSend, error, dataFilter, success and complete).

tpeczek
`async: false` will freeze the browser UI while the requests are being made.
Justin Johnson
async:false - can be an option, thanks. But in case of 'success' or 'complete', it won't work as it will be the same with jQuery
glaz666
I really recommend to not use async: false, the user experience is never too good with those type of requests.
SBUJOLD
+2  A: 

Duplicate of http://stackoverflow.com/questions/2911822/javascript-execute-a-bunch-of-asynchronous-method-with-one-callback/2911891#2911891

function createCallback(limit, fn){
    var finishedCalls = 0;
    return function(){
        if (++finishedCalls == limit){
             fn();
        }
    };
}


var callback = createCallback(4, function(){
    alert("woot!");
});


async1(callback);
async2(callback);
async3(callback);
async4(callback);
Sean Kinsey
+1  A: 

Maybe you could 'cascade' the downloads, so the callback of the first getJSON triggers download from the next source, and so on? Then in the last callback you have no sources left and can call your 'done' function.

axel_c
Yes, that's a good idea! I'll try that and be back. But still a problem with failing response...
glaz666
@glaz666: Why can't you set a timeout or define an error callback that handles the error?
axel_c
@axel_c: How do I set timeout? :) Error call back is ok
glaz666
@glaz666: getJSON is just a shorthand method for $ajax. Use $.ajax() and pass dataType='json' and you can set timeout there (details at http://api.jquery.com/jQuery.ajax).
axel_c
A: 

Maybe I am wrong - but the rule is: serialization of AJAX - one at a time So you HAVE to chain it - each response (call back function) must submit the next one in turn

*.onreadystatechange will give you control (a function that is) )when it is ready - here you can submit the next one in turn

Mike
+1  A: 

I asked the same question a while ago and got a couple of good answers: http://stackoverflow.com/questions/2208710/best-way-to-add-a-callback-after-a-series-of-asynchronous-xhr-calls/2208860#2208860

SBUJOLD