Consider:
angular
.module('app', [])
.controller('MainController', function($scope) {
$scope.$watch('bool', function(newVal, oldVal) {
});
console.log($scope);
});
and
<body ng-controller='MainController'>
<p ng-class="{'blue': bool, 'red': !bool}">ngClass</p>
<p ng-show='bool'>ngShow</p>
<input type='checkbox' ng-model='bool' />
</body>
plnkr of above
It seems that there are 3 watchers being created:
$scope.$watch
.ngShow
.ngClass
.(Note: directives involved in data binding use $scope.$watch internally.)
I would have thought that since they're all watching the bool
property, there'd only be one watcher and it'd have multiple listener callbacks.
Edit: is it the case that it's saying, "Has bool
changed? If so run cb1
. Has bool
changed? If so run cb2
. Has bool
changed? If so run cb3
." Or is it the case that it's saying, "Has bool
changed? If so run cb1
, cb2
, and cb3
." If the former, why do that over the latter?
Questions:
bool
3 times instead of 1?Example for 2) - say you want to make sure that two passwords in a form match, and if they don't, show an error. Assume that you already have:
ng-class="{invalid: myForm.myInput1.$touched && ctrl.myInput1 != ctrl.myInput2}"
Say you want to use $setValidity
to update the validity of the form. Might it be a good idea to do:
ng-class="{invalid: myForm.myInput1.$touched && ctrl.functionToCheckInputs(myForm)}"
and call $setValidity
inside of functionToCheckInputs
rather than using $scope.$watch
and doing $setValidity
inside of it? Because the latter adds an additional watcher (presumably).
So, apparently, in Angular, the digest cycle doesn't run only once. Instead, it keeps running until all the variables are set to the right value. In simpler words, the digest cycle will keep running on for a finite number of times, until all the elements' values are set.
watchers is nothing but dirty checking, which keeps a track of the old value and new value. They are getting evaluated on each digest cycle. It can be combination of scope variable or any expression. Angular does collect all of this watchers on each digest cycle and mainatain it inside $$watchers array.
The Scope in AngularJS is the binding part between HTML (view) and JavaScript (controller) and it is a built-in object. It contains application data and objects. It is available for both the view and the controller. It is an object with available properties and methods. There are two types of scopes in Angular JS.
There are multiple $watchers being registered. In fact, even if you had 2 exact expressions:
$scope.$watch("foo", cb1)
$scope.$watch("foo", cb2)
you'd still get 2 $watchers.
To answer your question - it is the former case, i.e. "if "foo"
expression changed, run cb1
, if "foo"
expression changed, run cb2
, etc... Why? Because, any $watcher could potentially change the return value of $scope.foo
; not just in the callback, but in the expression itself. Angular needs to re-evaluate the expressions every time to account for that possibility.
The length of the digest cycle plays a significant factor on performance.
First, is the number of $watchers, which cause a watched expression or function to evaluate. So, reducing the number of $watchers, like preferring one-way to two-way watch, or use one-time watch where suitable, improves performance.
Second, is the complexity of the watched functions. These functions should be very fast - ideally, not more than getters. For example, avoid the following:
<div ng-class="{active: isActive(id)}">
$scope.isActive = function(id){
for (var i=0; i<items.length; i++){
if (items[i].id == id && items[0].active) return true;
}
return false;
};
Is my interpretation correct? Are there actually multiple watches being registered?
So to answer this I refer back to a another very good stack article. How to count total number of watches on a page?
This was great pre angular AngularJS 1.3.2 when a countWatchers method was added to the ngMock module.
Now you can count the number of watches on the item, which you are correct, there are 3 two way relationships that have been created that will watch.
What are the implications for performance?
This is a little harder to quantify, the more watchers the less performance it will have. My suggestion would be to use Batarang to judge the performance of your watchers to insure you are not bloating your app. https://chrome.google.com/webstore/detail/angularjs-batarang-stable/niopocochgahfkiccpjmmpchncjoapek
Also approx 2000 watches in my own personal apps is when I have noticed significant performance issues.
Bonus: if my interpretation is correct and multiple watchers are being added, why would it be designed like this? Why look for changes to bool 3 times instead of 1?
Watching is made up of a two way relationships. This has been one of the struggles with angular because there is a fast way of doing something in angular and a more optimal way. If you had made that markup be a directive with bool used in a template then there would have been only 1 watch linked to the directive. Angular 2.0 should improve upon this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With