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.
Related
I have an angular (9) component which gets BehaviourSubjects. I learn from many sources like this to use the async-pipe when displaying observables content (instead of subscribing it in ngInit). There's also the trick, using *ngIf* with as to not repeat it all the time. But since they are BehaviourSubjects after all, I could could simply do
<div>{{behaviourSubject.getValue()}}</div>
or whatever. Actually it's seems much cleaner to me then using 'async' and practically leads to less problems here and there. But I am nor sure if this is an okay pattern or has it serious disadvateges?
I'd refer you to Ben Lesh's (author of RxJS) answer on this topic here
99.9% of the time you should NOT use getValue()
There are multiple reasons for that...
In Angular, you won't be able to use the OnPush ChangeDetectionStrategy. Not using it makes your app slower because Angular will constantly try to sync the value with the cached view value. In your case, it even needs to call the getValue function first.
When the BehaviourSubject errors or completes you'll not be able to call getValue.
Generally the use of getValue, and I'd argue even BehaviourSubject, is not necessary, because you can express most Observables by only using pipeable operators on another source Observable. The only real place where Subjects are necessary is when you need to convert an otherwise unobservable event to an Observable.
While it might look cleaner not to use async, you're actually moving the hard work to Angular which needs to do figure out when it should call getValue().
BehaviorSubject often live inside services in order to dispatch new values to other services/components to keep them up to date.
A good practice is to declare the BehaviorSubject as private and to only exposes him .asObservable(), so consumers aren't allowed to change its value directly.
That's why we have to use the async pipe on the provided observable source.
Second reason: async pipes are automatically unsubscribing from the observables they're fed with. [Edition]: as the comparison is with .getValue() which provide the value of the subject without the need to subscribe, there is no explicit benefit of the pipe of a subject in this use case.
Calling methods within templates expressions would be the first thing you would want to avoid in Angular.It is considered bad practice to call a method within the template.Click here for more information around that.
As Gerome mentioned, it would be a right approach to expose behaviour subject as an observable and subscribing to it within the template using async pipe, and since its a behaviour subject, it will always have latest values emitted as well on subscription, hence you can avoid using getValue() method as well.
If your property is of BehaviourSubject type it's totally fine to use getValue() in the template. The difference between getValue() and | async as value is that getValue() is called every time of change detection to detect rerender case, but because there's nothing behind than return this._value it's totally fine.
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 know a lot of the big name MVC, M** style JavaScript frameworks allow 2-way binding with Observables.
Meaning if I:
Update a DOM input filed, it will also update a JavaScript object variable which could also save to server with AJAX request.
If I update the JavaScript object variable, it will also in turn update the DOM text field.
As I am learning JavaScript, I would love to skip the big name libraries and learn how to do this in it's most basic raw JavaSript form.
Can anyone provide quick easy to understand demo of this functionality without using libraries like BackboneJS, Knockout, Angular, or others?
jQuery is acceptable.
I would appreciate the lesson and help please.
This is different in every framework.
Angular for instance saves every variable on scopes. Iterate through the scopes variables and compare the values with the previous ones and if there is a change it is carried out to the DOM.
This check is made upon they call digest cycles. If one cycle is finished it calls again until every variable 'observed' is the same as it was in the previous cycle. You can also add objects or vars to this 'observer'.
Angular keeping the view current, with calling this digest every time something could change the 'observed' vars, like http calls, user interactions ... but for instance, if you change a variable outside from angular (console), than the variable change is not carried out to the DOM. You have to call a digest cycle manually to do so.
In HTML5 it is a bit easier with Object.observe, but it is not yet supported in every browser currently on the market.
Hope I could help
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.