When discussing the merits of AngularJS, two-way data binding is often touted as a major benefit of Angular over other JS frameworks. Digging deeper, the documentation suggests
Short direct answer to the main question is "NO", angular doesn't automatically trigger digest loop.
TL;DR answer:
Digest loop is designed to run dirty check over POJO models associated with Angular scope instances, so it only needs to run when a model might be changed. In a single page Web application running inside Browser, the following actions/events could lead to a model change
Correspondingly, Angular trigger digest loop at, for instance
Try to answer those bonus questions from my understanding:
So some key practices for avoid angular performance pitfalls are
Angular digests are triggered - they don't happen through polling.
Code executes, after code is done, angular triggers a digest.
Example:
element.on('click', function() {
$scope.$apply(function() {
// do some code here, after this, $digest cycle will be triggered
});
});
Angular will also trigger a $digest after the compile/link phase:
Compile > Link > Digest
And as to how many digest cycles are triggered? It depends on how soon the scope variables stabalise. Usually it takes at least 2 cycles to determine that.
I believe this is what happens. AngularJS made a smart assumption that model changes happen only on user interaction. These interactions can happen due to
AngularJS directives for the corresponding events wrap the expression execution in $scope.$apply as shown by @pixelbits in his example. This results in digest cycle.
There are some other events too where AngularJS triggers the digest loop. $timeout service and the $interval service are two such examples. Code wrapped in these service also results in digest loop to run. There maybe be some other events\services that can cause digest cycles to execute but these are the major ones.
This is the very reason that changes to model outside the Angular context does not update the watches and bindings. So one needs to explicitly call $scope.$apply. We do it all the time when integrating with jQuery plugins.