Digest loop is responsible for two way data binding in AngularJS so that to update DOM elements with the changes made to the model as well as executing any registered watcher functions.
The $digest loop is fired when the browser receives an event that can be managed by the angular context. This loop is made up of two smaller loops. One processes the $evalAsync queue and the other one processes the $watch list.
The $digest loop keeps iterating until the $evalAsync queue is empty and the $watch list does not detect any changes in the model. The $evalAsync queue contains those tasks which are scheduled by $evalAsync() function from a directive or controller.
The $watch list contains watches correspondence to each DOM element which is bound to the $scope object. These watches are resolved in the $digest loop through a process called dirty checking. The dirty checking is a process which checks whether a value has changed, if the value has changed, it set the $scope as dirty. If the $scope is dirty, another $digest loop is triggered.
When you do the changes to the scope outside the angular context, you have to call $apply() function explicitly on the scope to trigger $digest cycle immediately.