AngularJS – an awesome framework with lots of native services and functions. Some of them are $apply, $timeout, $digest and $evalAsync. These are pretty used terms in any of the AngularJS apps, but sometimes these are a bit confusing with actual differences between them. So I decided to dig them down a bit further. Let’s see what I found for them.
$apply() is the function which is responsible to execute the entire list of watchers of all available scope in the application by invoking $digest on rootScope ($rootScopr.$digest()). This means that every time we call $apply() we execute a new life complete cycle of the application.
As per AngularJS documentation:
The expression is executed using the $eval() method.
Any exceptions from the execution of the expression are forwarded to the $exceptionHandler service.
The watch listeners are fired immediately after the expression was executed using the $digest() method.
In actual scenarios, it is rare when we need to invoke $apply manually because all native AngularJS services automatically wrap in it. It is only needed when we use any 3rd party library because Angular does not aware about changes made by any 3rd party library, so we explicitly wrap our code in $apply.
In the below example, the first code will not update the binded UI control with “message” while second will do that because “setTimeout” is not natively part of AngularJS.
If we use $apply heavily in the application, we might get the Error: $digest already in progress. It happens because one $digest cycle can be run at a time. We can resolve it by $timeout or by $evalAsync.
2) $digest :
AngularJS executes in cycles, which is termed as “$digest” and this “$digest” is responsible for evaluating changes between models and views and update UI and Model to be in sync.
As already described above that $apply invokes $digest on rootScope and its means that it reevaluate all watchers in all available scope and this may cause a performance hit for large scope hierarchy.
Sometimes we only want to re-evaluate specific scope and its children and this can easily achieve by invoking $digest() on desired scope. It is important to know that the parent scope is not being updated with the new information, hence the changes won’t be reflected if the expression is also used by the parent scope but for any child scope it will reflect.
3) $timeout :
$timeout() was the easiest available solution to resolve problems related to invoking code outside the Angular environment prior to AngularJS 1.2.X.
The $timeout does not generate error like „$digest already in progress“ because $timeout tells Angular that after the current cycle, there is a timeout waiting and this way it ensures that there will not any collisions between digest cycles and thus output of $timeout will execute on a new $digest cycle.
$evalAsync() is a new function which was first introduced in AngularJS 1.2.X, and in my opinion it is the adroit version of $timeout().
Before $evalAsync() came into the picture, AngularJS team recommended using the $timeout in case of digest cycle issue, described above.
As AngularJS evolved for large apps and digest cycle became common and then Angular team introduced $evalAsync(). This function will evaluate the expression during the current cycle or the next.
Ok, let me explain a little bit more about it.
Suppose you call some expression on $evalAsync and any digest cycle is going on at the same time. All expressions from $evalAsync will be added to the queue and they will be part of the current lifecycle and no new digest cycle will be invoked. This is why $evalAsync make it more efficient because it reduce the possibility to create new digest every time.
If there is not any digest is going on, it will work similar to $timeout. It will create a callback with default time (10 ms) and after this time (10 ms), there will be a new digest on rootScope and all expressions will be evaluated.
AngularJS : $apply vs $timeout vs $digest vs $evalAsync was last modified: July 28th, 2015 by Rahul Garg