问题
I'm coming from Knockout and I'm trying to understand how Angular updates the scope. I'm a bit confused as to why a function defined on the scope (e.g. $scope.doStuff = function()) gets executed on every single scope refresh.
Plnkr link: http://plnkr.co/edit/YnvOELGkRbHOovAWPIpF?p=preview
For example:
HTML
<div ng-controller="one">
<input type="text" ng-model="a">
{{b()}}
</div>
JS
angular.module('test', [])
.controller('one', ['$scope', function ($scope) {
$scope.a = 'one';
$scope.b = function () {
console.log('b has executed');
}
}])
So whenever an event happens in the input form field for $scope.a, function $scope.b gets executed. Why does that happen? There are no dependencies on that function, it seems inefficient that it is always refreshing.
If I add another controller in the same structure, like such:
HTML
<div ng-controller="one">
<input type="text" ng-model="a">
{{b()}}
</div>
<div ng-controller="two">
<input type="text" ng-model="x">
{{y()}}
</div>
JS
angular.module('test', [])
.controller('one', ['$scope', function ($scope) {
$scope.a = 'one';
$scope.b = function () {
console.log('b has executed');
}
}])
.controller('two', ['$scope', function ($scope) {
$scope.x = 'two';
$scope.y = function () {
console.log('y has executed');
}
}])
Every time I update $scope.a in controller one the output is:
b has executed
y has executed
Why is controller two executing $scope.y? I thought creating a new controller creates a new child scope. Is it because the child scopes are linked to the parent scope?
More interestingly, if I update $scope.x in controller two then the output is:
b has executed
y has executed
b has executed <-- a second time... what?
Why does function $scope.b get executed a second time?
So why do functions in Angular get executed on every scope refresh?
回答1:
Angular uses what is called dirty checking. In order to maintain the binding between the view and controller, any variable which is tied to a function must be validated.
Using like you have demonstrated is generally a bad idea and can effect performance of a medium to large scale app.
Using fixed variables to bind to the view and changing when required is recommended, this will lead to greater performance overall and only re-render the parts that have changed.
In general you don't 'call' the function from the view, but sometimes this is the only way if using dynamic data in a ng-repeat then I would place that data into a object/array and return that object/array, then even tho angular will continue to call the function on it's digest cycle it won't 'update' the view if not changed.
回答2:
Here I get think so, each time the page load, angular js initiates that function, that means each time the page load the will be executed so instead calling directly, call it using the ng-change.
<div ng-controller="one">
<input type="text" ng-model="a" ng-change=b()>
</div>
<div ng-controller="two">
<input type="text" ng-model="x" ng-change=y()>
</div>
And in controller you can assign that function to your required ng-model as follows,
angular.module('test', [])
.controller('one', ['$scope', function ($scope) {
$scope.b = function () {
$scope.a = 'one';
console.log('b has executed');
}
}])
.controller('two', ['$scope', function ($scope) {
$scope.y = function () {
$scope.x = 'two';
console.log('y has executed');
}
}])
Or else you can also return the function value to the your ng-model by assiging to ng-model and it will give your correct answer rather than calling each time.
回答3:
simply because it's impossible to know what are all the dependencies on a function. let's say your function b ( on controller one) would be like this :
$scope.b = function () {
console.log('b has executed');
another_func($scope);
}
and the definition of the function another_func would be like this :
function another_func (obj) {
obj.a = 'something';
return obj.a;
}
how can you programmatically know that the function $scope.b would call a function that will call another function to get a value that depends on $scope.a ?
来源:https://stackoverflow.com/questions/29474445/why-does-angularjs-execute-function-on-every-digest-loop