Spencer Davis
Spencer Davis

Reputation: 171

If I execute a function which makes an asyncronous call, how do I make the rest of the function wait for the call before executing if doing a loop?

I have a function like this inside an angularJS app

function Validate() {
    var inputs = $scope.getInput;
    var defer = $q.defer();
    var promises = [];
    _.each(inputs, function(input) {
      promises.push(loadInformation(input)
        .then(function(inputList) {
            repository.calculation(inputList, input);

            if (inputList) {
                return true;
            }
            else {
                return false;
            }
        }));
});
$q.all(promises).then(function() {
    for (var i = 0; i < promises.length; i++) {
        if (!promises[i]) {
            defer.reject();
        }
    }
    defer.resolve(); // after it loops get the answer
});
return defer.promise;
}
function handleAction(event) {
    if (Validate().value) {
        alert('show success');
    }
    else {
        alert('show failue');
    }
    alert('this is being hit before callback finishes');
}

I start the execution in handleAction(event) and it starts the Validate() async function. It goes through it and does nothing basically, then it executes the rest of handleAction(event) and it gives the alert

'this is being hit before callback finishes'

then before it reaches the end of the function it goes back to the async call and finishes executing.

2 questions: Am I doing promises correct?
Also how do I make the alert('show success') or alert('show failure') to wait until the call is completely done and returns a result?

Upvotes: 0

Views: 54

Answers (1)

Mathew Berg
Mathew Berg

Reputation: 28750

You just have to change your handleAction to use the promise instead:

function Validate() {
    var inputs = $scope.getInput;
    var promises = [];
    _.each(inputs, function (input) {
        promises.push(loadInformation(input)
            .then(function (inputList) {
                repository.calculation(inputList, input);

                if (inputList) {
                    return true;
                } else {
                    return false;
                }
            }));
    });
    return $q.all(promises)
        .then(function (results) {
            for(var x = 0; x < results.length; x++){
                if(!results[x]){
                    return $q.reject("Rejected");
                }
            };
            return "Resolved";
        });
}
function handleAction(event) {
    var validatePromise = Validate();
    validatePromise.then(function(data){
        //data === "Resolved"
    }, function(error){
        //error === "Rejected"
    });
}

A few other things of note, once you've done something to a promise (reject/resolve) you shouldn't do one of those again so I modified that to do a return. Also you can pass in data to both resolve/reject. In the example I just pass in a string. Also instead of creating a defer you can just return the $q.all. At the same time checking if !promise[i] won't work as that's actually set. You have to check the result which I showed how to above.

Upvotes: 1

Related Questions