2015-04-06 61 views
2

我来自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中的函数会在每个范围刷新上执行?

+0

角度必须确保没有改变视图,因此它执行你在视图内使用的所有函数,并且检查视图内是否使用了所有变量 – Grundy

+0

因此,如果我有一个包含1000个项目的'ng-repeat',并且每个人都有一个'ng-show =“函数()”'这意味着每次更新文本字段时,Angular将执行该函数1000次?这似乎是糟糕的表现明智的。 – Andrew

+1

所以不要使用它1000个项目:-) – Grundy

回答

3

Angular使用所谓的脏检查。为了维护视图和控制器之间的绑定,必须验证绑定到函数的任何变量。

使用就像你已经证明一般是一个坏主意,可以影响大中型应用程序的性能。

建议使用固定变量绑定到视图并在需要时进行更改,这将导致整体性能更高,并且只重新渲染已更改的部件。

一般而言,您不会从视图中调用该函数,但有时这是在ng-repeat中使用动态数据的唯一方法,那么我会将该数据放入对象/数组中并返回该对象/ array,那么即使tho角将继续调用它的摘要循环上的函数,如果没有改变,它不会'更新'视图。

+1

哦......我明白了!这是有道理的。因此,另一种完成我想要做的事情的方法是在不同的上下文中评估函数,并将结果存储在作用域中,之后Angular将通过脏检查来获取更改。谢谢! – Andrew

1

只是因为不可能知道函数的所有依赖关系。让我们假设你的函数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

+0

这很有道理,谢谢你的解释。也许这超出了这个问题的范围,但是有什么办法限制函数何时执行?在Knockout中,你可以触发一个函数,只有在函数中的依赖项改变时才能执行,是否有类似的方式来实现Angular中的相同事情? – Andrew

2

在这里我会这样想,每当页面加载时,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-模型模型,它会给你正确的答案,而不是每次调用。