如何優化在大型 AngularJS 專案(2)
parse 和 $interpolate
優化可以呼叫 $parse 一次然後將其返回的函式
這個函式可以被$eval呼叫多次,如下
- 優化前
for (let index = 0; index < 9999; index++) { $scope.$eval('exp') }
- 優化後
var parsedExp = $parse('exp') for (let index = 0; index < 9999; index++) { parsedExp($scope) }
- 優化前
myApp.directive(function(){ return{ link:function(scope, element, attr){ scope.name = scope.$eval(attr.name); scope.$watch(attr.list, function(list){ //程式碼 },true); } } })
- 優化後
myApp.directive(function($parse){ return{ //這裡避免使用 link 因為如果這個 directive在迴圈體中 //使用,這個 link 可能多次執行,而 compile 僅被執行 //一次。 compile:function(elem, attr){ var nameExp = $parse(attr.name), listExp = $parse(attr.list); return function link(scope, elem){ //當要觀察一個數組或物件時,使用 $watchCollection 代替 $watch scope.$watchCollection(listExp,function(list){ //程式碼 }) } } } })
interpolate 速度快的,儘量作為首選
如果沒有必要儘量不要使用 $watch
通常會使用 $watch 來觀察一個物件內部深層的屬性,如果這樣
不要觀察整個物件,剝去不管緊要的層,只關注要觀察的屬性即可
- 優化前
$scope.$watch('listOfBigObjects',myHandler, true);
- 優化後
$scope.$watch(function($scope){ return $scope.listOfBigObjects.map(function(bigObject){ return bigObject.name.submane; }) },myHandler, true)
使用 ng-repeat 時需要使用 track by $index
預設情況(也就是不使用 track by $index 時),ng-repeat 為每個遍歷物件
建立一個 dom 節點然後remove後銷燬它,
而使用 track by $index 會進建立一次 dom 節點,然後複用它
- 優化前
<div ng-repeat="item in array"> {{item}} 建立一個 dom </div>
- 優化後
<div ng-repeat="item in array track by $index"> {{item}} 僅建立一個 dom </div>
ng-show 和 ng-if
ng-show接收的一個bool值,當為true的時候就會被觸發去展示DOM節點。
當ng-show的值為false的時候,在DOM節點上添加了一個ng-hide的一個類,
這個類的表示式就是“display:none”。
DOM load的時候ng-show裡面的所有節點都會被載入。
也就是說,ng-show僅僅是影藏和顯示了DOM節點。
也就意味如果油太多的ng-show指令,即使他們不顯示,但他們所在的DOM節點還是會被渲染的。
ng-if也接收的一個bool值,當它的值為false的時候,
它所控制的節點並沒有被建立或者說之前的DOM節點會被銷燬掉,
哪怕這個節點裡麵包含了很多ng的繫結都不會去執行。
所以,我們在專案開發中,如果沒有必要一次性載入完的dom就可以用
ng-if來阻止ng事件發生,從而也就加快了dom的載入速度。
特別是在repeat的時候,每條資料又包含了複雜的資料結構的時候效果特別明顯。
當它的值為true的時候,就會去建立DOM節點。
可以使用僅繫結一次
- 繫結一次
var watcher = $scope.$watch('data', function(newValue, oldValue) { if (newValue) { watcher(); } });