The "real" answer to this question, and one you are not going to like, is:
"you can't"
When you make a change to a model in Angular, you have absolutely no idea how many $digest() calls are going to be required to fully materialize the DOM.
Let's say you have a very large array foos - it' has one million elements.
In your markup, you do the following:
<div ng-repeat="foo in foos"><div ng-if="foo.somecondition">I'm a visible foo!></div></div>
In you controller, you set foos:
.controller('myController', function($scope, $fooService) {
$scope.foos = $fooService.get();
$timeout(function(){
//foo array done? Not quite!!!!
});
});
(get() is not asynchronous in this example, it returns the array of foos immediately).
After the controller constructor is run, $digest() will (eventually) run by Angular. This digest cycle will generate one million rows in the DOM (which will take a long time and will lock the browser while the DOM is being modified). At the end of the digest, if you used $timeout in the controller, your $timeout function would fire, BUT the DOM would not yet be fully built.
If examined the DOM at that very second, you'd find that you had your million rows, but the inner ng-if would not have been evaluated yet. Angular, at the end of the first digest cycle, would have noted that another digest cycle was needed and it would go right into running the next digest cycle - after your $timeout was evaluated.
Of course, this is a rather contrived example. It get's worse if you are loading in data asynchronously, etc.
I would recommend the real problem is that your foo data is too big - without knowing the details of your implementation, I can't offer much to help figure out how you would better manage the problem.
The key is that in Angular, you only worry about the state of the model, not the state of the DOM.
If I were going to try to display an array of a million foos, in order to keep the browser responsive, I would do it something like this:
.controller('myController', function($scope, $fooService) {
$scope.loading = true;
$scope.foos = [];
var length = $fooService.length; //1,000,000 foos
var i = 0;
var loadFoos = function() {
var count = 0;
while(count < 10) {
$scope.foos.push($fooService.get(i + count++));
if(i + count == length) {
$scope.loading = false; //we're done!
return;
}
}
i += count;
//note, using setTimeout vs. $timeout deliberately - I want each digest cycle to completely finish and return the control of the execution context to the browser.
setTimeout(function(){
$scope.$apply(function() {
loadFoos();
}, 0);
})
};
loadFoos(); //kick things off.
});
What I'm doing is loading foos 10 at a time and then returning control to the browser in the interim. You can now use the $scope.loading flag to indicate that foos are still loading, and all will work. I threw this together pretty quick as an example to get the point across - I'm sure there are ways to make it a little more elegant and it might even have a few syntax errors.
If I were doing this "for real" I'd probably wrap this functionality into the service itself.