Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm a little confused how to determine when async function called multiple times from another one is finished a call from the last iteration:

function MainAsyncFunction(callback) {
  for (var i = 0; i < 10; i++) {
    SubAsyncFunction(function(success) {
      if (i >= 10 && success) { // THIS IS WRONG?!
        callback(true); // happens too early
      }
    });
  }
};

function SubAsyncFunction(callback) {
  SubSubAsyncFunction(function() {
        callback(true);
  });
}

What I'm doing is calling the Google Distance Matrix service, which has a limitation of 25 destinations, hence I'm having to split my array of destinations to call this service multiple times but I don't understand when it's finished.

and in the main bit of code I can tell that the second iteration of the loop in the MainAsyncFunction hasn't yet completed when it does a call back.

I think my problem is I haven't got my head around the order of events when dealing with Async functions in JavaScript... please explain how the subject is normally achieved.

share|improve this question

3 Answers 3

up vote 6 down vote accepted

You could use the jQuery Deferred object, which acts as a token representing the status of an async operation.

The following is a simplified example:

//set up your sub method so that it returns a Deferred object
function doSomethingAsync() {
    var token = $.Deferred();
    myAsyncMethodThatTakesACallback(function() {
        //resolve the token once the async operation is complete
        token.resolve();
    });
    return token.promise();
};

//then keep a record of the tokens from the main function
function doSomethingAfterAllSubTasks() {
    var tokens = [];
    for (var i=0; i < 100; i++) {
        //store all the returned tokens
        tokens.push(doSomethingAsync());
    }

    $.when.apply($,tokens)
        .then(function() {
            //once ALL the sub operations are completed, this callback will be invoked
            alert("all async calls completed");
        });
};

The following is an updated version of the OP's updated code:

function MainAsyncFunction(callback) {
  var subFunctionTokens = [];
  for (var i = 0; i < 10; i++) {
    subFunctionTokens.push(SubAsyncFunction());
  }

  $.when.apply($,subFunctionTokens)
  .then(function() {
    callback(true);
  });
};

function SubAsyncFunction() {
  var token = $.Deferred();
  SubSubAsyncFunction(function() {
        token.resolve();
  });
  return token.promise();
};​
share|improve this answer
    
i have simplified my code, would this still work for me? –  Tsar Mar 29 '12 at 15:06
    
Yes, this would still work. Give me a moment and I'll convert your new code... –  Steve Greatrex Mar 29 '12 at 15:16
    
@Tsar see my edit –  Steve Greatrex Mar 29 '12 at 16:17
    
hey, I do like the idea but don't fully understand implementation and unfortunately it doesn't work for me. Here's a jsFiddle: jsfiddle.net/BBjbK –  Tsar Mar 30 '12 at 12:49
    
@Tsar, thats because I made a mistake in the code - $.when doesn't take an array so we need to use apply to get it working. I've updated the fiddle here: jsfiddle.net/stevegreatrex/BBjbK/3 –  Steve Greatrex Mar 30 '12 at 13:13

Perhaps the ajaxStop() event? This is a jQuery event that only fires when all active AJAX requests are completed.

share|improve this answer

The problem is that the value of i is constantly changing in the loop, finally being out of bounds after failing the loop conditional.

The easiest way to fix this is:

for( i=0; i<5; i++) { // or whatever your loop is
    (function(i) {
        // the value of i is now "anchored" in this block.
    })(i);
}
share|improve this answer
    
Or use $.each(data, function(index, item) { ... }) –  Steve Greatrex Mar 29 '12 at 14:15
    
If you want to bloat the code by another several hundred commands for no good reason, sure, knock yourself out... –  Niet the Dark Absol Mar 29 '12 at 14:20
    
Assuming you're referring to jQuery, the OP's already using it (he's included the tag) so he gets each for free and I personally think its a little more readable. Point taken though –  Steve Greatrex Mar 29 '12 at 14:33
    
What I meant is that calling each adds another massive number of commands for JS to execute, whereas mine is as simple as it gets. I don't approve of jQuery in general for this reason. Every site I've seen that uses it lags in all browsers and all computers I test in... Meanwhile I produce similar or better effects in raw JS and have to double-check if it's supposed to go that fast. –  Niet the Dark Absol Mar 29 '12 at 14:38
    
hi the problem is different, it calls back too early - the problem is my criterion for MainFunction callback. I need to know when the very last SubFunction call is processed. –  Tsar Mar 29 '12 at 14:43

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.