標籤:hash 其他 高度 padding 更新 div element 期望 apply
AngularJS作為強大的前端MVVM架構,雖然已經做了很多的效能最佳化,但是我們開發過程中的不當使用還是會對效能產生巨大影響。
下面提出幾點最佳化的方法:
1. 使用單次綁定符號{{::value}}
AngularJS的效能最佳化方法之一是減少雙向繫結。我們知道AngularJS的雙向繫結是通過為每個需要雙向繫結的資料對象添加$$watchers,一旦某個scope的資料發生了更新,就觸發髒檢測($digest),深度優先遍曆所有scope對象的$$watchers值的old/new value是否發生變化。所以在開發過程中,我們都要小心判斷建立出的每個$$watchers是否有必要。對於只需要更新一次,以後不管資料層如何變化都不需要更新的資料,使用連續兩個冒號即可在在$$watchers列表中將這個值刪除,即減少了$digest髒檢測迴圈。
2. ng-repeat最佳化
第一種方式雖然減少了髒檢測的次數,但是單次繫結資料畢竟少數,可能加完單次綁定,效能提升並沒有太大。如果我們的代碼中使用了ng-repeat,並且list數量很大時,我們的效能會有很大下降,在移動端尤為明顯。下面幾點是對ng-repeat指令的最佳化。
- 使用limitTo來減少第一次載入列表元素的數量,以提高初始化頁面的速度。我們也許有上百上千條資料要顯示,但是螢幕的大小畢竟有限,呈現在使用者眼前的可能就是個1280x800或者360x640大小的螢幕,那我們可以先載入使用者所能看到幾個十幾個列表。limitTo屬性就提供了這樣的功能。
<li ng-repeat="mail in mails |limitTo:loadMailLimitTo"></li>
<ul> <li ng-repeat="mail in mails"> {{mail.id}}:{{mail.title}} </li></ul>
如果我們想更新mails裡面的值,我們可能會這麼做:
| 1 |
$scope.mails = newMailListFromServer; |
上一行代碼會告訴ng-repeat去刪除掉所有的li元素,再去重建一套新的li,這意味著大量的DOM操作,尤其當li元素裡面有 複雜的邏輯判斷和雙向繫結資料。這是因為ng-repeat在建立時會給每個mail加上$hashkey屬性,並時時跟蹤,一旦mails元素替換成伺服器 返回的對象,即時他們完全一樣,由於他們沒有$hashkey,所以ng-repeat不會知道他們是一樣的元素。而通過如下的改動:
<li ng-repeat="mail in mails track by mail.id"></li>
ng-repeat會跟蹤我們建立的mail.id去判斷是否為新的元素。這樣就減少了大量的DOM刪減添加操作。
需要注意的是,如果limitTo和track by一起使用的時候,需要把track by放到最後,如
<li ng-repeat="mail in mails | limitTo:loadMailLimitTo track by mail.id"></li>
- 如果有引入ionic架構,可以使用collection-repeat替代ng-repeat。
collection-repeat是ionic架構自己的一套顯示list的指令,原理在於不論list有多大,頁面最多隻有一定數量的item,這個item數量的大小是通過螢幕高度和單個item的高度計算出來的。滑動列表時通過更新item元素的頁面內容和位置來呈現所有的items。所以在大數量級的list呈現上,collection-repeat會比ng-repeat效能好很多。但是需要注意的是,由於collection-repeat是通過時時更新滑動位置的item內容來實現的,所以在item內部使用第一個方法的單次綁定方式,滑動後會造成頁面混亂的情況。
3. 減少html頁面中的filter
原因是每當filter執行時,都會走兩次$digest cycle,一次是scope中有資料改動,一次是查看是否有更多的改動需要更新資料。當資料量很大時對效能會有很大影響。我們可以在初始化時就格式化好資料,比如賦值到view層之前,在我們的js代碼裡使用angular提供的$filter provider來預先處理我們的資料。
4. ng-if替代ng-show/ng-hide
原因是ng-if與ng-show/ng-hide的不同之處在於,ng-if在等於false時會把元素從DOM中移除,所以所有綁在該元素上的handler會一同失效。而ng-show/ng-hide不會移除DOM元素,而是使用css style去隱藏/顯示DOM元素,所以handlers會一直存在。
5. $scope.$apply()和$scope.$digest()
我們會用到上面兩種去執行一次髒檢測,重新整理頁面資料。區別就是$scope.$apply()會從$rootscope開始,深度優先遍曆執行$digest迴圈,而$scope.$digest會從當前scope開始,往下層scope遍曆髒檢測。如果只是期望當前scope的資料更新,而不涉及到parent $scope,則可以使用$scope.$digest()。
6. angular animate
如果我們的項目引入了angular-animate.js的模組,那麼在大部分使用了指令的元素上,animate裡面的代碼都會被執行,不管當前元素是否有應用css動畫樣式。這對我們頁面上如果有大量資料頻繁滑動,隱藏顯示的時候會有比較明顯的效能問題。如果我們對當前scope並沒有漸入漸出等動畫效果的時候,可以在當前scope初始化時加上$animate.enabled(false);當然,我們也可以對某個元素進行禁止動畫的動作:$animate.enabled(element, false);
7. ionicSlideBox最佳化(只針對使用了ionic架構的項目)
- 初始化slidebox時先初始化顯示中間的首先顯示在使用者面前的slide,其他的slide可以在$timeout裡面延遲初始化。思想和ng-repeat的limitTo比較類似。
- slidebox的滑動速度在ionic架構中預設速度是300ms滑完一個slide,通過改變這個速度來使滑動更快速。
基於AngularJS/Ionic架構開發的效能最佳化