2015-04-06 110 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-模型模型,它會給你正確的答案,而不是每次調用。