Wednesday, November 4, 2015

Getting Inside Angular: Can a Digest Continue Forever?

No, but let's look at why.

It is very plausible that you could create a situation where a series of watchers that made changes to the scope would lead to the current digest cycle continuing forever. When performing a $digest, all the watchers are checked for changes and only when no changes are detected, does the digest end (from a high level this is true, but the actual change detection algorithm is optimized so that the final cycle is terminated early when it reaches the last watcher that registered a change). During each cycle, if at least one change is made to an attribute that is being watched, this would lead to a never ending digest as one change would trigger another and so on. Luckily the Angular team thought of this!


Time To Live is the mechanism that keeps a record of how many cycles the digest has performed and will end the current digest if is reaches its 11th; in other words, a digest will terminate if it exceeds 10 cycles.

A simple way to create a situation where a watched attribute is being changed with each cycle of a digest is to use a counter and have the listener function increment its value:

$scope.counter = 0;
var removeWatch = $scope.$watch(
  function (scope) { return scope.counter; },
  function (newValue, oldValue, scope) { scope.counter++; }

After 10 cycles, the digest cycle terminates and an error is generated:

Details of the watchers that were fired in the last five iterations are included to help identify what caused the digest to continue to the TTL limit.

Any undetected changes will remain so until the next digest is run. No future digest is scheduled in this situation as that would essentially be a continuation of the current digest. It is also worth noting that the $$postDigest queue is not flushed when a digest is terminated and won't be until the next digest cycle successfully ends.

View on Plunker (open the developer tool's console).

You'll probably never run into this scenario, but it's good to know that the digest has got your back!

//Code, rinse, repeat