advanced20 min

The Digest Cycle

What $digest and $apply do, and why later frameworks moved away from this model.

What you'll learn

  • Explain what the digest cycle checks for and why it exists
  • Describe when $apply is needed to trigger a digest manually
  • Explain why later frameworks moved away from AngularJS's digest-cycle model

Explanation

The digest cycle is AngularJS's mechanism for detecting changes and updating the DOM -- conceptually similar in purpose to change detection in modern Angular (if you've taken that course), but implemented very differently. AngularJS registers a watcher for every binding/expression it needs to track, and $digest repeatedly re-checks every registered watcher's current value against its previously-recorded value ("dirty checking"), updating the DOM for anything that changed -- and re-running the whole check again if anything did change, until nothing changes anymore or a maximum iteration count is hit.

AngularJS automatically triggers $digest after things it's aware of (an ng-click handler, an ng-model-bound input event, an AngularJS-provided $http response). The trouble comes when your code changes $scope data from outside something AngularJS is watching for -- a raw setTimeout, a third-party library's callback, a native (non-AngularJS) event listener. In those cases, AngularJS has no idea a change happened, and the view silently doesn't update until something else happens to trigger a digest. The fix is calling $scope.$apply(() => { /* your change */ }) explicitly, which makes the change and then manually triggers a digest.

This dirty-checking-every-watcher approach is exactly the kind of implementation detail that becomes a real performance concern as an application's watcher count grows (a large ng-repeat-heavy page can register thousands of watchers), and it's one of the concrete, well-documented reasons later frameworks (modern Angular, React, Vue) moved to different change-detection/reactivity models entirely.

Guided lab

Predict: Dirty checking detecting a changed watcher

AngularJSNot executed
This lab does not run in your browser or on VisaSparkSchools's servers. Read the code, predict what it does, then reveal the real expected output.

This models one digest pass: check every watcher's current value against its last-recorded value, and report which ones changed. Predict the output.

const watchers = [
  { name: "username", lastValue: "ada", getCurrentValue: () => "ada" },
  { name: "count", lastValue: 3, getCurrentValue: () => 5 },
  { name: "isValid", lastValue: false, getCurrentValue: () => false },
];

for (const watcher of watchers) {
  const current = watcher.getCurrentValue();
  if (current !== watcher.lastValue) {
    console.log(`${watcher.name} changed: ${watcher.lastValue} -> ${current}`);
  }
}

Stuck? Get a hint.

Common mistakes

  • Changing $scope data inside a raw setTimeout or third-party callback and being confused why the view doesn't update -- AngularJS doesn't know to run a digest unless you call $scope.$apply().
  • Calling $scope.$apply() when already inside a digest cycle (e.g. inside an ng-click handler, which already triggers one), causing a 'digest already in progress' error.
  • Assuming digest-cycle performance issues are rare -- a large ng-repeat list can register enough watchers to make this a real, measurable problem.

Knowledge check

Knowledge check

1. What does the digest cycle do, at its core?
2. When is $scope.$apply() typically needed?
3. What is a well-documented real-world consequence of the digest-cycle model at scale?

Takeaway

The digest cycle dirty-checks every registered watcher -- call $scope.$apply() when changing $scope from outside AngularJS's awareness, and expect real performance costs from large watcher counts.

Summary

The digest cycle repeatedly dirty-checks watchers to detect changes; $apply manually triggers it for changes AngularJS wouldn't otherwise notice; watcher count is a genuine performance concern at scale.

References

Your notes

Notes save automatically.

Finished this lesson?

Mark it complete to track your progress and schedule a future review.

Next: The $http Service