为什么AngularJS在每个摘要循环上执行函数?
我来自Knockout,我想了解Angular如何更新范围。我有点困惑,为什么在范围上定义的函数(例如$scope.doStuff = function()
)在每个范围刷新上都被执行。为什么AngularJS在每个摘要循环上执行函数?
Plnkr链接:http://plnkr.co/edit/YnvOELGkRbHOovAWPIpF?p=preview
例如:
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');
}
}])
所以每当一个事件发生在$scope.a
的输入表单字段中,函数$scope.b
被执行。为什么会发生?这个函数没有依赖关系,它总是令人耳目一新,效率不高。
如果我在同一结构中添加其他控制器,就像这样:
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');
}
}])
我每次在控制器one
更新$scope.a
输出是:
b has executed
y has executed
为什么控制器two
执行$scope.y
?我想创建一个新的控制器创建一个新的子范围。是否因为子范围链接到父范围?
更有趣的是,如果我更新控制器two
$scope.x
那么输出是:
b has executed
y has executed
b has executed <-- a second time... what?
为什么功能$scope.b
得到执行第二次?
那么为什么Angular中的函数会在每个范围刷新上执行?
Angular使用所谓的脏检查。为了维护视图和控制器之间的绑定,必须验证绑定到函数的任何变量。
使用就像你已经证明一般是一个坏主意,可以影响大中型应用程序的性能。
建议使用固定变量绑定到视图并在需要时进行更改,这将导致整体性能更高,并且只重新渲染已更改的部件。
一般而言,您不会从视图中调用该函数,但有时这是在ng-repeat中使用动态数据的唯一方法,那么我会将该数据放入对象/数组中并返回该对象/ array,那么即使tho角将继续调用它的摘要循环上的函数,如果没有改变,它不会'更新'视图。
哦......我明白了!这是有道理的。因此,另一种完成我想要做的事情的方法是在不同的上下文中评估函数,并将结果存储在作用域中,之后Angular将通过脏检查来获取更改。谢谢! – Andrew
只是因为不可能知道函数的所有依赖关系。让我们假设你的函数b
(在控制器one
)会是这样的:
$scope.b = function() {
console.log('b has executed');
another_func($scope);
}
和功能another_func
的定义是这样的:
function another_func (obj) {
obj.a = 'something';
return obj.a;
}
如何通过编程知道该功能$scope.b
会调用一个函数来调用另一个函数来获得一个值取决于$scope.a
?
这很有道理,谢谢你的解释。也许这超出了这个问题的范围,但是有什么办法限制函数何时执行?在Knockout中,你可以触发一个函数,只有在函数中的依赖项改变时才能执行,是否有类似的方式来实现Angular中的相同事情? – Andrew
在这里我会这样想,每当页面加载时,angular js启动该函数,这意味着每次页面加载时都会执行,所以直接调用它,使用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>
并在控制器,可以进行如下的功能分配给您的要求NG-模型,
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');
}
}])
要不然你也可以通过assiging为NG而返回的函数值到您的NG-模型模型,它会给你正确的答案,而不是每次调用。
角度必须确保没有改变视图,因此它执行你在视图内使用的所有函数,并且检查视图内是否使用了所有变量 – Grundy
因此,如果我有一个包含1000个项目的'ng-repeat',并且每个人都有一个'ng-show =“函数()”'这意味着每次更新文本字段时,Angular将执行该函数1000次?这似乎是糟糕的表现明智的。 – Andrew
所以不要使用它1000个项目:-) – Grundy