AngularJS在大型單頁面應用中的效能優化(一)

edithfang發表於2015-01-03
1.簡介

無論你正在編寫一箇舊的應用程式還是在一個大型應用中採用AngularJS,效能是一個重要的方面。瞭解是什麼原因導致AngularJS應用程式慢下來非常重要,要知道,在開發過程中做出權衡是很重要的。本文將介紹一些AngularJS比較常見的效能問題,以及優化的建議。

2. 效能測試工具

本文采用jsPerf http://jsperf.com/ 效能測試的基準。

3.軟體效能

評價軟體效能有兩個基本的因素:

首先是演算法的時間複雜度。一個簡單的例子就是線性搜尋和二分檢索有著非常顯著的效能差距。

第二個軟體緩慢的原因被稱為空間複雜度。這是一臺電腦需要多少“空間”或記憶體執行你的應用程式。記憶體需求越多,執行速度就越慢。

4 Javascript的效能

有些效能問題不僅僅是Angular帶來的,而是JavaScript本來就有的。

4.1 迴圈

避免在迴圈內部呼叫函式,可以移到外部呼叫。

var sum = 0;
for(var x = 0; x < 100; x++){
  var keys = Object.keys(obj);
  sum = sum + keys[x];
}

上面的方面明顯沒有下面的快:

var sum = 0;
var keys = Object.keys(obj);
for(var x = 0; x < 100; x++){
  sum = sum + keys[x];
}

4.2 DOM訪問

在獲取DOM元素時要注意

angular.element('div.elementClass')

這種方式是非常昂貴的。其實這在AngularJS中並不會引起太大的問題。但是留意一下是有好處的。DOM樹要小,DOM的訪問要儘可能的少。

4.3變數作用範圍垃圾回收

把你的變數作用範圍限制地越緊密越好,這樣垃圾回收器就可以更快地回收空間。注意下面的問題:

function demo(){
    var b = {childFunction: function(){
        console.log('hi this is the child function')
    };
    b.childFunction();
    return b;
}

當這個函式終上了,這裡就沒有到b的引用。b就會被回收了。但是如果有這樣一行:

var cFunc = demo();

這個引用就會阻止垃圾回收。要儘量避免這類引用。

4.4 陣列和物件

這裡有很多點:

比如:
for (var x=0; x<arr.length; x++) {
    i = arr[x].index;
}

比這一種快一點(注*arr為陣列, obj為json物件)

for (var x=0; x<100; x++) {
    i = obj[x].index;
}

比這一種更快一點

var keys = Object.keys(obj);
for (var x = 0; x < keys.length; x++){
  i = obj[keys[x]].index;
}

測試: http://jsperf.com/array-vs-object-perf-demo

5重要的概念

我們已經討論過有關JavaScript的效能,現在有必要看一看AngualrJS中的核心概念,看看它究竟是怎麼運作的。

5.1 域(Scopes)和更新週期(DigestCycle)

Angular的域本質上是一些JavaScript物件,它們從一些預定義的物件繼承而來。基本上,小的域比大的域執行要快。

換句話說,每建立一個新的域,都會給垃圾回收器新增更多待回收的內容。

在寫AngularJS應用中尤其要注意的一個核心概念和效能影響方面是更新週期(DigestCycle)。實際上每一個域都會存放一個由方法組成的陣列 $$watchers。

每當域中的一個值(屬性)或繫結的DOM,如ng-repeat,ng-switch 和 ng-if 等等,呼叫 $watch時,一個函式(function)就會新增到相對應域中的$$watchers陣列佇列中。

當域中的值發生改變時,在$$watchers中所有的watchers函式都會被觸發呼叫。並且當它們的任何一個修改了域中的某個值時,它們會被再次觸發執行。

這個過程會一直迴圈下去直到$$watcher陣列佇列中不再做任何更改或丟擲異常為止。

更外如果任何程式碼執行$scope.$apply(),都會觸發更新週期。

最後一點是$scope.evalAsync() 會在一個非同步呼叫中執行,並且在當前和下個執行週期中,不會呼叫其的更新週期。

6. 在設計Angular時應該遵守的一般準則

6.1大型物件和伺服器呼叫

所以這些都告訴了我們什麼?首先我們要儘可能地簡化我們的物件。當物件是從伺服器返回時,這一點尤為重要。

直接將資料庫中的一行轉換成物件只是臨時性方案,因此不要使用.toJson().

只需要把Angular需要的屬性值返回回來。

6.2 監視函式(Watching Functions)

另一個常見的問題是為觀察者繫結的函式。不要將任何東西(ng-show,ng-repeat等等)直接繫結到一個函式。不要直接監視任何函式的返回值。該函式會在每個更新週期都執行,可能會降低你應用的速度。

6.3 監視物件(WatchingObjects)

同樣,Angular提供了第三個可選引數來監視整個物件的改動。將呼叫$watch的第三個引數設為true。這是一個非常可怕的想法。一個更好的解決辦法是依靠服務和物件的引用,監視域之間的變化。

原文地址: airpair.com
相關閱讀
評論(1)

相關文章