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 this process is done through dirty-checking rather than through event-driven measures. At first, it seems that the digest-loop works by having a method fire off in the background at periodic intervals, checking all the $watches during each cycle. However, reading further, it seems that the digest-loop is actually triggered by rootScope.digest(), which in turn is triggered by $.apply, which is in turn triggered by an event(!), such as an onClick event called through ng-click.
But, how can this be? I thought Angular doesn't use change listeners. So how does the digest-loop really operate? Does Angular automatically kick-off the digest-loop internally, or is the digest-loop triggered by events? If the digest-loop is run automatically, how often does it run?
Some clarification points:
I'm not asking about how the digest-loop runs when manually binding to changes. In this case, if you want to force a digest loop, you can do so by calling $.apply()
I'm also not asking about how often digest loop runs in response to user events. For example, if ng-model is on an input box, Angular will kick-off a digest loop when a user starts typing. The confusing part is that in order to know a user was typing, doesn't Angular use an event-based onKeyUp somewhere?
I already know that there is a limit of 10 cycles max per digest-loop. My question is less about the number of cycles per digest-loop, but rather the number of digest-loops that run, say, per second.
Bonus questions: How does the digest-loop relate to the JavaScript event-loop? Does the JS event loop run periodically in the background? Is the digest-loop the same thing as the event loop, but only in the "Angular Context"? Are these totally different ideas?
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.
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
DOM events
XHR responses firing callbacks
Browser's location changes
Timers (setTimout, setInterval) firing the callbacks
Correspondingly, Angular trigger digest loop at, for instance
input directives+ngModel, ngClick, ngMouseOver etc.
$http and $resource
$location
$timeout
Try to answer those bonus questions from my understanding:
ngModel directive often used with angular input directives (text, select etc) together, and the laters will listen on "change" events and call $setViewValue API exposed from ngModelController in order to sync back dom value. During the sync process, ngModelController will make sure to trigger digest loop.
digest loop is different from JS event loop, the later is concept of JS runtime (checkout the great visualised session https://www.youtube.com/watch?v=8aGhZQkoFbQ) which run against event queue and remove consumed event from the queue automatically, but digest loop never remove watch from its watch list unless you explicitly unwatch.
the number of digest loops per second depends on the efficiency of all watch callbacks being executed through the loop . If some bad code took one second to finish, then this digest loop would cost more than 1 sec.
So some key practices for avoid angular performance pitfalls are
Watch callback should be coded as simpler/efficient as possible, for example detach complicated algorithm code to, for example, worker threads
Proactively remove a watch if it is not used anymore
Prefer to call $scope.$digest() instead of $scope.$apply() if applicable, $digest() only run part of scope tree and ensure the models associated under the subtree is reflecting to view. But $apply() will run against entire scope tree, it will iterate through more watches.
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
Mouse activity (move, clicked etc)
Keyboard activity (key up, key down etc)
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.
Related
Problem
While the $digest-cycle in my app still runs quite fast, i noticed that some callbacks (which are bound in the templates for example via ng-if) are called way more often than i expected. This goes up to 100+ calls on a single UI-interaction (where I would generally expect something between 3 or 10 calls at most).
I would like to understand why the callbacks are called this often and possibly reduce the number of calls to prevent future performance Issues.
What I tried
From my understanding the described behaviour means that the $digest-cycle takes up to a few-hundred loops to remove all dirty-flags and make sure that all rendered nodes are up-to-date.
I simplified several callbacks to just return true - instead of evaluating some model-values - which had no effect on the number of $digest calls at all. I also checked the Performance-Tab in the Chrome-developer-Tools which only told me that the calls themselves are executed within a few ms.
For trouble-shooting i also removed several ng-repeat blocks and angular-filters throughout the application since those obviously apply several watches to be evaluated in the $digest loop. This had no impact on the number of calls to the callback-functions either.
Thus i guess i need a more sophisticated tool or method to debug the (number of) $digest calls throughout my application to even figure out where all those calls are coming from and how to reduce them.
Questions
Which tools and methods can I use to evaluate the performance of the $digest-loop (and especially the number of loops) in my angular-application?
How do I reduce the number of calls to callbacks which are bound in a template?
I think to answer the second question it would already be helpful to understand what can cause additional calls to foo() in a setup like this:
<div ng-if="ctrl.foo()">
<!--<span>content</span> -->
</div>
First thing what does actually digest cycle in angularJS?
1. Its process in which angular framework check for all two way binding variable changes by its own continuously.
2. When ever user interact and change two way binding variable then it get fire.
3. programmatically(in controller, service or factory) two way binding variable get changed
Above are reasons to fire digest cycle call...
Which entity are part of digest cycle?
1. $watch added on variables.
2. ngModel, ng-model iteself internally add $watch on varaible
Basically $watch function.
What we can do to avoid $digest/avoid call to $watch?
Think about variable using in UI that does this variable need to be two way binding?
If answer is NO then just go for one-way bind syntax
Avoid use of watch function from controller, service, factory
Then how can I watch it...
RX js is right now best library which can help to overcome this issue. Its just one option.
Use getter setter
How?
mymodule.controlle('ctrName', ctrClass);
ctrClass {
constructor($scope) {
this.myVar1 = null;
this.myVar2 = null;
}
set myVar1(value) {
// either code which i want in watcher
// or
// Some function which i want to execute after value get set
this.afterSet();
return this.myVar1 = value;
}
afterSet() {
}
}
Use controllerAs feature of angular
Create directives with isolated scopes
About tool:
To validate angular application Batarange is good tool.
In Angular 1.x we use to have digest cycle which triggers the watchers and update the view whenever there is a change in the binded property.
In Angular 2 we see that there is interpolation(one way binding) of properties in view when there is a change so how does this one way binding works under the hood.
Can someone please explain this?
Thanks
I found few pointers which suggested that there is something called Zone.js which helped getting away with digest cycle and $apply in angular 2.
Angular 1
When you write an expression ({{aModel}}), behind the scenes Angular sets up a watcher on the scope model, which in turn updates the view whenever the model changes
$scope.$watch('aModel', function(newValue, oldValue) {
//update the DOM with newValue
});
The second argument passed to $watch() is known as a listener function, and is called whenever the value of aModel changes. It is easy for us to grasp that when the value of aModel changes this listener is called, updating the expression in HTML.
$digest cycle is responsible for firing the watchers.The $digest cycle starts as a result of a call to $scope.$digest().
Angular doesn’t directly call $digest(). Instead, it calls $scope.$apply(), which in turn calls $rootScope.$digest(). As a result of this, a digest cycle starts at the $rootScope, and subsequently visits all the child scopes calling the watchers along the way.
for more detail plz visit : Angular Digist cycle
Angular 2
Basically application state change can be caused by three things
1.Events - click, submit, …
2.XHR - Fetching data from a remote server
3.Timers - setTimeout(), setInterval()
They are all asynchronous. Which brings us to the conclusion that, basically whenever some asynchronous operation has been performed, our application state might have changed. This is when someone needs to tell Angular to update the view.
Angular allows us to use native APIs directly. There are no interceptor methods we have to call so Angular gets notified to update the DOM.
Zones take care of all these things. In fact, Angular comes with its own zone called NgZone
The short version is, that somewhere in Angular’s source code, there’s this thing called ApplicationRef, which listens to NgZones onTurnDone event. Whenever this event is fired, it executes a tick() function which essentially performs change detection.
for more please visit : Angular 2 change detection
Basically, AngularJS was all about Two-way databinding, that ended up being very costly in terms of ressource usage with the $scope and the $watchers. You could always do One-way databinding, but that was not well made for that and it became hard to work with AngularJS.
With Angular2, since it's a different Framework, you can do both pretty easily.
Here is a good link that explains the different databindings possibilities :
http://tutlane.com/tutorial/angularjs/angularjs-data-bindings-one-way-two-way-with-examples
There are even more differences between those two Frameworks that you should learn about.
Here are some cool links that I discovered a few months ago that are quite helpful to understand why they went from AngularJS to Angular2 and contain all the answers you are looking for :
http://blog.mgechev.com/2015/04/06/angular2-first-impressions/
http://angularjs.blogspot.fr/2015/09/angular-2-survey-results.html
https://dzone.com/articles/typed-front-end-with-angular-2
Zone.js is something else :
https://github.com/angular/zone.js/
Have fun reading !
My app seems to have views with a lot of logic in them. My question is two fold:
Does logic in the view slow down angular app performance?
As a best practice, is it better to treat this logic in the controller and just store the outcome in a $scope attribute which the view can access ?
Would this improve performance ?
Example of views in our app (a simple one):
<div class="small-12 column" id="notificationMsg">
{{ config.message | translate : config.getMessageParams(notification)}}
</div>
short answer:
yes
long answer:
your bindings will have to be updated in every digest cycle which affects the used variables.
storing the value in a variable and only updating it if something changes will improve your performance.
however this will only be critical if you reach a certain amount of complexity. as long as your app doesn't grow too much this won't be a threat to think about - yet.
i wouldn't necessarily call it a best practice, because it can make your code more complex and harder to read/understand/maintain.
performance isn't always an issue. it just starts to be one as soon as it's absent by default ;)
a further improvement you can do is use ng-bind and ng-bind html instead whenever possible, because it can be rendered faster, since it can skip some internal steps of angularJS whilst compiling the expression.
so e.g. use
<div ng-bind="foo"></div>
instead of
<div>{{ foo }}</div>
if possible
The key concept behind these performance considerations is reducing the number of $$watchers inside Angular to improve the $digest cycle’s performance, something you’ll see and hear more of as you continue working with Angular. These are crucial to keeping our application state fast and responsive for the user. Each time a Model is updated, either through user input in the View, or via service input to the Controller, Angular runs something called a $digest cycle.
This cycle is an internal execution loop that runs through your entire application’s bindings and checks if any values have changed. If values have changed, Angular will also update any values in the Model to return to a clear internal state. When we create data-bindings with AngularJS, we’re creating more $$watchers and $scope Objects, which in turn will take longer to process on each $digest. As we scale our applications, we need to be mindful of how many scopes and bindings we create, as these all add up quickly - each one being checked per $digest loop.
Angular runs every single filter twice per $digest cycle once something has changed. This is some pretty heavy lifting. The first run is from the $$watchers detecting any changes, the second run is to see if there are further changes that need updated values.
Here’s an example of a DOM filter, these are the slowest type of filter, preprocessing our data would be much faster. If you can, avoid the inline filter syntax.
{{ filter_expression | filter : expression : comparator }}
Angular includes a $filter provider, which you can use to run filters in your JavaScript before parsing into the DOM. This will preprocess our data before sending it to the View, which avoids the step of parsing the DOM and understanding the inline filter syntax.
$filter('filter')(array, expression, comparator);
Yes, for better performance, Use
$scope.description: $translate.instant('DESCRIPTION')
in Controller, instead of,
{{'DESCRIPTION' | translate }}
Furthermore,
It depends on what you want to achieve. Here is another way to increase performance.
One Time Binding
Angular 1.3 added :: notation to allow one time binding. In summary, Angular will wait for a value to stabilize after it’s first series of digest cycles, and will use that value to render the DOM element. After that, Angular will remove the watcher forgetting about that binding.
I want to allow a user to search for a location with the Google Places API, and then when they click on a given location, to update the value of a parameter on the scope.
Hopefully some visuals will help:
So the Google part works correctly. However, when the user clicks on "New South Wales", this is the following result of evaluating {{ table.newItem }}:
As you can see, the value on my scope has not updated due to the user's click event.
I'm not familiar with how to use $watch() or $apply(). Could any of those be useful here?
Also, where should I be placing this code? Right now it is in a link function, so that I can target the input box on a click event. Should it go somewhere else?
Wrap the logic where you set the scope variable in $scope.$apply.
$scope.$apply(function () {
// modify scope here
});
The reason is that Angular has an event loop known as the digest cycle. It's always running. During a digest cycle Angular will process its data model, detect any changes, and then update the UI to reflect the updated data model. This all works great when the data model is updated at the proper moment during the digest cycle.
When you use external libraries you'll often end up tying code to triggers that happen outside of Angular's digest cycle. For example, even a simple setTimeout would fire outside of a digest cycle because it would be fired off by the JavaScript engine itself in a later iteration of the JavaScript event loop.
When this happens, the data model does change as you expect it to, but the UI update portion of the digest cycle doesn't run because Angular has not detected the change yet. If you perform another operation (even an unrelated one) to modify scope inside a proper digest cycle, then suddenly you'd see the UI update to reflect those changes plus the changes you made outside of a digest cycle.
You would have to wrap the contents of the timeout in $scope.$apply to ensure that Angular is aware of the changes and can update any UI components appropriately.
// Won't update any UI bound to "message" properly
// until something else triggers a UI update in a later digest cycle.
setTimeout(function () {
$scope.message = "hi";
}, 0);
// Will update the UI immediately as expected because you're manually
// telling Angular to run the logic during a digest cycle.
setTimeout(function () {
$scope.$apply(function () {
$scope.message = "hi";
});
});
This is also the reason angular provides a $timeout service of its own. It's literally just an angular service that wraps setTimeout and does the $scope.$apply for you behind the scenes.
Any logic inside the callback passed to $scope.$apply will be held and executed during a digest cycle at the proper moment, allowing Angular to update the UI normally with up to date data from the data model.
I haven't worked with the Google Maps API but I'm pretty certain you're probably hooking into a callback or event that is fired/triggered by the Google Maps API. If that's the case, wrap the logic in that handler in $scope.$apply and you're good to go.
I was reading some article to understand a little bit more how AngularJS works.
One of the terms that I didn't understand is Dirty Checking.
What is it exactly? It seems like the Observer pattern but apparently it's better.
Can you help me understand this please?
EDIT : it can be also useful for people who wants to learn more about that to watch this video from swiip at NgEurope some years ago.
From this link:
Angular defines a concept of a so called digest
cycle. This cycle can be considered as a loop, during which Angular
checks if there are any changes to all the variables watched by all
the $scopes. So if you have $scope.myVar defined in your controller
and this variable was marked for being watched, then you are
explicitly telling Angular to monitor the changes on myVar in each
iteration of the loop.
This "digest" is also called "dirty checking", because, in a way, it scans the scope for changes. I cannot say if it's for better or for worse than observable pattern. It depends on your needs.
Some links:
Angular documentation
A blog post about Angular scopes
Angular Dirty Checking mechanism workflow.
Dirty checking is a simple process that boils down to a very basic
concept: It checks whether a value has changed that hasn’t yet been
synchronized across the app.
Our Angular app keeps track of the values of the current watches.
Angular walks down the
$watch list, and, if the updated value has not changed from the old
value, it continues down the list. If the value has changed, the app
records the new value and continues down the $watch list.
Check out the whole article here
What is dirty checking?
The process of checking every watch to detect the changes, is called dirty checking. There could be two scenarios
First –
Get a watch from list
Check whether item has been changed
If there is no change in item then
No Action taken, move to next item in watch list
Second–
Get a watch from list
Check whether item has been changed
If there is Change in an item
DOM needs to be updated, return to digest loop
In second case, loop continues till it finds no changes in the entire loop. And once it completes, DOM gets updated if required.
Just modifying a previous answer...
Angular has a concept of ‘digest cycle’. You can consider it as a loop. In which Angular checks if there are any changes to all the variables watched by all the $scopes (internally $watch() and $apply() functions are getting bonded with each variable defined under $scope).
So if you have $scope.myVar defined in your controller (that means this variable myVar was marked for being watched) then you are explicitly telling Angular to monitor the changes on myVar in each iteration of the loop. So when the value of myVar changes, every time $watch() notices and execute $apply() to apply the changes in DOM.
This "Digest" is also called "dirty checking", because, in a way, it scans the scope for changes. As all watched variable are in a single loop (digest cycle), any value change of any variable forces to reassign values of other watched variables in DOM.
PROS: This is the way Angular achieves Two-way data binding.
CONS: If there are more watched variables in a single page (>2000–3000), you may see lag while page loading. (But I say if there are that many ‘watched variables’ in a single page, it is a bad page design :p).
There are other cons, as well as are workarounds also :D
Dirty checking
will check anything changes in $scope variable and update it to the DOM.
This done by angular js, you can also implement dirty checking by your own.
I read a great article about dirty checking in this blog post. There was also this SO answer
TLDR; version
When the $digest cycle kicks in, the watchers will check for any changes in the scope model and if there are any (the change might also come from out-of-Angular-domain), the corresponding listener functions are executed. This will again run the $digest loop and checks if the scope model was changed (the listener function could also modify the scope model).
Overall, the $digest cycle will run twice even if the listener does not change the model or till it hits the max loop count of 10.