7 簡單的效能改進
1)謹慎使用 ng-repeat
在檢視中使用 ng-repeat
通常會導致效能不佳,尤其是當存在巢狀的 ng-repeat
時。
這超級慢!
<div ng-repeat="user in userCollection">
<div ng-repeat="details in user">
{{details}}
</div>
</div>
儘量避免巢狀重複。提高 ng-repeat
效能的一種方法是使用 track by $index
(或其他一些 id 欄位)。預設情況下,ng-repeat
跟蹤整個物件。使用 track by
,Angular 僅通過 $index
或 object id 觀察物件。
<div ng-repeat="user in userCollection track by $index">
{{user.data}}
</div>
**使用其他方法,**如分頁 ,虛擬滾動 ,無限滾動或限制:儘可能開始,以避免迭代大型集合。
2)繫結一次
Angular 具有雙向資料繫結。如果使用太多,它會降低成本。
效能較差
<!-- Default data binding has a performance cost -->
<div>{{ my.data }}</div>
更快的效能 (AngularJS> = 1.3)
<!-- Bind once is much faster -->
<div>{{ ::my.data }}</div>
<div ng-bind="::my.data"></div>
<!-- Use single binding notation in ng-repeat where only list display is needed -->
<div ng-repeat="user in ::userCollection">
{{::user.data}}
</div>
使用 bind once
表示法告訴 Angular 在第一系列摘要週期後等待值穩定。Angular 將在 DOM 中使用該值,然後刪除所有觀察者,使其成為靜態值,並且不再繫結到模型。
{{}}
慢得多。
這個 ng-bind
是一個指令,它將在傳遞的變數上放置一個觀察者。因此,當傳遞的值確實發生變化時,ng-bind
將僅適用。
另一方面,托架將在每個 tihuan 11 中進行髒檢查和更新,即使沒有必要。
3)範圍功能和過濾器需要時間
AngularJS 有一個摘要迴圈。你的所有功能都在檢視中,並且每次摘要週期執行時都會執行過濾器。每當模型更新時都會執行摘要迴圈,它可能會降低你的應用程式速度(在載入頁面之前可以多次點選過濾器)。
避免這個:
<div ng-controller="bigCalulations as calc">
<p>{{calc.calculateMe()}}</p>
<p>{{calc.data | heavyFilter}}</p>
</div>
更好的方法
<div ng-controller="bigCalulations as calc">
<p>{{calc.preCalculatedValue}}</p>
<p>{{calc.data | lightFilter}}</p>
</div>
控制器可以是:
app.controller('bigCalulations', function(valueService) {
// bad, because this is called in every digest loop
this.calculateMe = function() {
var t = 0;
for(i = 0; i < 1000; i++) {
t += i;
}
return t;
}
// good, because this is executed just once and logic is separated in service to keep the controller light
this.preCalulatedValue = valueService.valueCalculation(); // returns 499500
});
4 位觀察者
觀察者的表現大幅下降。對於更多的觀察者,摘要迴圈將花費更長時間,UI 將減慢。如果觀察者檢測到變化,它將啟動摘要迴圈並重新渲染檢視。
在 Angular 中有三種方法可以手動監視變數的變化。
$watch()
- 值得改變
$watchCollection()
- 手錶收藏變化(手錶超過常規 $watch
)
$watch(..., true)
- 儘可能避免這種情況,它將執行深度觀察並將降低效能(手錶超過 watchCollection
)
請注意,如果你要在檢視中繫結變數以建立新手錶 - 請使用 {{::variable}}
來防止建立手錶,尤其是在迴圈中。
因此,你需要跟蹤你正在使用的觀察者數量。你可以使用此指令碼統計觀察者(歸功於 @Words 像 Jared 觀察者數量 )
(function() {
var root = angular.element(document.getElementsByTagName('body')),
watchers = [],
f = function(element) {
angular.forEach(['$scope', '$isolateScope'], function(scopeProperty) {
if(element.data() && element.data().hasOwnProperty(scopeProperty)) {
angular.forEach(element.data()[scopeProperty].$$watchers, function(watcher) {
watchers.push(watcher);
});
}
});
angular.forEach(element.children(), function(childElement) {
f(angular.element(childElement));
});
};
f(root);
// Remove duplicate watchers
var watchersWithoutDuplicates = [];
angular.forEach(watchers, function(item) {
if(watchersWithoutDuplicates.indexOf(item) < 0) {
watchersWithoutDuplicates.push(item);
}
});
console.log(watchersWithoutDuplicates.length);
})();
5)ng-if / ng-show
這些功能在行為上非常相似。 ng-if
從 DOM 中刪除元素,而 ng-show
只隱藏元素但保留所有處理程式。如果你有部分程式碼不想顯示,請使用 ng-if
。
這取決於使用型別,但通常一個比另一個更合適。
-
如果不需要該元素,請使用
ng-if
-
要快速開啟/關閉,請使用
ng-show/ng-hide
<div ng-repeat="user in userCollection"> <p ng-if="user.hasTreeLegs">I am special<!-- some complicated DOM --></p> <p ng-show="user.hasSubscribed">I am awesome<!-- switch this setting on and off --></p> </div>
如有疑問 - 請使用 ng-if
並測試!
6)禁用除錯
預設情況下,繫結指令和作用域在程式碼中留下額外的類和標記,以協助各種除錯工具。禁用此選項意味著你不再在摘要週期中呈現這些不同的元素。
angular.module('exampleApp', []).config(['$compileProvider', function ($compileProvider) {
$compileProvider.debugInfoEnabled(false);
}]);
7)使用依賴注入來公開你的資源
依賴注入是一種軟體設計模式,其中物件被賦予其依賴性,而不是建立它們自身的物件。它是關於刪除硬編碼的依賴關係,並使其可以在需要時更改它們。
你可能想知道與所有可注入函式的字串解析相關的效能成本。Angular 通過在第一次之後快取$ inject 屬性來解決這個問題。因此,每次需要呼叫函式時都不會發生這種情況。
PRO TIP:如果你正在尋找效能最佳的方法,請使用$ inject 屬性註釋方法。這種方法完全避免了函式定義解析,因為這個邏輯包含在 annotate 函式中的以下檢查中:if(!($ inject = fn。$ inject))。如果$ inject 已經可用,則不需要解析!
var app = angular.module('DemoApp', []);
var DemoController = function (s, h) {
h.get('https://api.github.com/users/angular/repos').success(function (repos) {
s.repos = repos;
});
}
// $inject property annotation
DemoController['$inject'] = ['$scope', '$http'];
app.controller('DemoController', DemoController);
專題提示 2:你可以在與 ng-app
相同的元素上新增 ng-strict-di
指令,以選擇嚴格的 DI 模式,只要服務嘗試使用隱式註釋,就會丟擲錯誤。例:
<html ng-app="DemoApp" ng-strict-di>
或者如果你使用手動引導:
angular.bootstrap(document, ['DemoApp'], {
strictDi: true
});