AngularJs ng-repeat 必須注意的性能問題


AngularJs 的 ng-repeat 讓我們非常方便的遍歷數組生成 Dom 元素,但是使用不當也會有性能問題。

在項目中我們使用 ng-repeat 加載完一個列表后,如果再次請求數據,然后過濾列表,代碼可能會這么寫:

<div ng-controller="Test">
    <button ng-click="request()">請求新數據</button>
    <div ng-repeat="user in users">
        {{user.name}}
    </div>
</div>

Controller 的代碼:

app.controller('Test', function($scope) {
    var users = [];
    for (var i = 0; i < 100; i++) {
        users[i] = {
            id: i,
            name: "User: " + i
        };
    }
    $scope.users = users;

    $scope.request = function () {
        // 從服務器加載新數據
        var result = [];

        // 直接重新賦值給 users
        $scope.users = result;
    };
});

查看 ng-repeat 的源碼可以發現,當 ng-repeat 的數組被替換時, 它默認並不會重新利用已有的 Dom 元素,而是直接將其全部刪除並重新生成新的數組 Dom 元素:

// 將上次生成的所有 dom 移除
for (key in lastBlockMap) {
    if (lastBlockMap.hasOwnProperty(key)) {
        block = lastBlockMap[key];
        elementsToRemove = getBlockElements(block.clone);
        $animate.leave(elementsToRemove);
        forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
        block.scope.$destroy();
    }
}

Dom 的頻繁操作是非常不友好的,為什么 ng-repeat 不能利用已有的 dom 元素去更新數據呢?因為你沒有把數組元素的標識屬性告訴它,那么兩次替換的時候它就沒辦法追蹤了,我們可以看到 ng-repeat 往數組里每個元素加了一個 $$hashKey 的屬性:

key

這個 key 是由 Angular 內部的 nextUid() 方法生成,類似數據庫自增,但是是使用字符串。

現在我們明白了,因為每次替換數組都會導致 ng-repeat 為每個元素生成一個新 key, 所以根本沒辦法重用已有的 Dom 元素,那么我們可以使用下邊的語法來避免這個問題:

<div ng-controller="Test">
    <button ng-click="request()">請求新數據</button>
	// 使用 track by 標識
    <div ng-repeat="user in users track by user.id">
        {{user.name}}
    </div>
</div>

這樣 ng-repeat 就用將其緩存起來啦,當然可能你的數組元素沒有一個標識屬性,如果元素數量不多那么可以接受,不然還是建議你手動為其生成一個標識屬性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM