{AnglarJS精華}性能の優れた7つの提案を行います.

8117 ワード

AnglarJSは優れたWebフレームとして、先端開発の負担を大きく減らすことができます.近日Sebastian Fromlstlは1篇の博文《AnglarJS》になります. Performance Tuning for Long Listsでは、AnglarJSが複雑なデータ構造を含む大規模なリストを扱う場合、運転速度が非常に遅くなることを示しています.彼は文の中で同時に解決策を共有した.以下はその文の翻訳文です.
    AnglarJSは素晴らしいですが、複雑なデータ構造を含む大型リストを扱うと、その運転速度は非常に遅くなります.これはコア管理ページをAnglarJSに移行する過程で発生した問題です.これらのページは500行のデータを表示する時にスムーズに働くべきですが、最初の方法のレンダリング時間はなんと7秒もかかりました.とても怖いです.
    その後,実現過程において2つの主要な性能問題が存在することを見出した.一つは「ng-repeat」です. ”コマンドに関連して、もう一つはフィルタに関連しています.
    以下は私達が異なった方法で性能問題を解決する経験を共有します.
    アングラーJS の中のng-repeatは大型リストを処理する時、速度はどうして遅くなりますか?
    AnglarJSのng-repeatは2500以上の双方向データバインディングを処理すると速度が遅くなります.これはAnglarJSが「dirty」を通過するためです. checking関数は変化を検出します.検出するたびに時間がかかります.複雑なデータ構造を含む大型リストは、あなたのアプリケーションの実行速度を低下させます.
性能向上の先決条件
    時間記録コマンド
    リストレンダリングにかかる時間を測定するために、簡単なプログラムを書きました.「ng-repeat」の属性「$last」を使って時間を記録します.時間はTimeTrackerサービスに預けて、このように時間記録はサーバー側のデータローディングと分離しました.
// Post repeat directive for logging the rendering time
angular.module('siApp.services').directive('postRepeatDirective', 
  ['$timeout', '$log',  'TimeTracker', 
  function($timeout, $log, TimeTracker) {
    return function(scope, element, attrs) {
      if (scope.$last){
         $timeout(function(){
             var timeFinishedLoadingList = TimeTracker.reviewListLoaded();
             var ref = new Date(timeFinishedLoadingList);
             var end = new Date();
             $log.debug("## DOM rendering list took: " + (end - ref) + " ms");
         });
       }
    };
  }
]);

// Use in HTML:
<tr ng-repeat="item in items" post-repeat-directive>…</tr>
    Chrome開発者ツールの時間軸属性
    Chrome開発者ツールの時間軸ラベルには、イベント、毎秒のブラウザフレーム数、メモリ割り当てが表示されます.メモリ漏れを検出するためのツール「memory」ツールと、ページに必要なメモリが使用されます.フレームレートが毎秒30フレーム以下の場合、ページが点滅します.ツールは、レンダリング性能の理解を助けることができます.JavaScriptタスクにかかるCPU時間を表示することもできます.
リストのサイズを制限することで基本的な調整を行います.
    この問題を緩和する一番いい方法は、表示されているリストのサイズを制限することです.ページを分割し、無限のスクロールバーを追加することで実現できます.
    改ページ
    改ページでは、AnglarJSの「limitTo」フィルタ(AnglarJS 1.1.4以降)と「startFrom」フィルタを使用できます.表示リストのサイズを制限することでレンダリング時間を減らすことができます.これはレンダリング時間を減らす最も効率的な方法です.
// Pagination in controller
$scope.currentPage = 0; 
$scope.pageSize = 75;
$scope.numberOfPages = function() {
    return Math.ceil($scope.displayedItemsList.length/ $scope.pageSize);
};

// Start from filter
angular.module('app').filter('startFrom', function() {
    return function(input, start) {         
        return input.slice(start);
};

// Use in HTML
// Pagination buttons
<button ng-repeat="i in getNumber(numberOfPages()) track by $index" ng-click="setCurrentPage($index)">{{$index + 1}}</button

// Displayed list
<tr ng-repeat="item in displayedItemsList | startFrom: currentPage * pageSize  | limitTo:pageSize" /tr>
    改ページが使えない場合、フィルタ処理が遅くなりますので、前の5ステップを確認して、「ng-show」を使って余分なリスト要素を隠します.
    無限スクロールバー
    この方法をもっと知りたいなら、訪問してもいいです. http://binarymuse.github.io/ngInfiniteScroll/」、
七大の法則
    1.データバインディングがないリストをレンダリングする
    これは最も明らかな解決策です.データバインディングは性能問題の最も可能な根源です.リストを表示するだけで、データを更新したり、変えたりする必要がないなら、データバインディングを放棄するのは素晴らしい方法です.しかし、残念なことに、データに対するコントロールを失うことになりますが、この方法を除いては選択できません.さらに理解してください. https://github.com/Pasvaz/bindonce.
    2.インライン方式でデータを計算しない
    コントローラで直接リストをフィルタリングするために、フィルタリングリンクを得る方法を使用しないでください. [$digest(http://docs.angularjs.org/api/ng.$rootScope.Scope($digest)%5 D表現.我々のケースでは、「filteredItems()」は、フィルタリングリンクに戻ります.評価プロセスが遅い場合、アプリケーション全体の速度を急速に低下させます.
/* Controller */
// Basic list 
var items = [{name:"John", active:true }, {name:"Adam"}, {name:"Chris"}, {name:"Heather"}]; 

// Init displayedList
$scope.displayedItems = items;

// Filter Cache
var filteredLists['active'] = $filter('filter)(items, {"active" : true});

// Apply the filter
$scope.applyFilter = function(type) {
    if (filteredLists.hasOwnProperty(type){ // Check if filter is cached
        $scope.displayedItems = filteredLists[type];
    } else { 
        /* Non cached filtering */
    }
}

// Reset filter
$scope.resetFilter = function() {
    $scope.displayedItems = items;
}

/* View */
<button ng-click="applyFilter('active')">Select active</button>
<ul><li ng-repeat="item in displayedItems">{{item.name}}<li></ul>
    3.2つのリストを使用します.(一つは表示用、一つはデータソースとして使用します.)
    表示するリストを全体のデータリストから分離することは、非常に有用なモデルです.フィルタリングのいくつかを前処理し、キャッシュに保存されているリンクをビューに適用します.以下の例は基本的な実現過程を示しています.filteredLists変数はキャッシュ中のリンクを保存し、appyFilter方法はマッピングを処理します.
/* Controller */
// Basic list 
var items = [{name:"John", active:true }, {name:"Adam"}, {name:"Chris"}, {name:"Heather"}]; 

// Init displayedList
$scope.displayedItems = items;

// Filter Cache
var filteredLists['active'] = $filter('filter)(items, {"active" : true});

// Apply the filter
$scope.applyFilter = function(type) {
    if (filteredLists.hasOwnProperty(type){ // Check if filter is cached
        $scope.displayedItems = filteredLists[type];
    } else { 
        /* Non cached filtering */
    }
}

// Reset filter
$scope.resetFilter = function() {
    $scope.displayedItems = items;
}

/* View */
<button ng-click="applyFilter('active')">Select active</button>
<ul><li ng-repeat="item in displayedItems">{{item.name}}<li></ul>
    4.他のテンプレートでは、ng-showの代わりに、ng-ifを使用します.
    コマンド、テンプレートを使って追加の情報をレンダリングする場合、例えばクリックしてリスト項目の詳細情報を表示する場合は、必ず使用してください.  ng-inf(AnglarJSv. 1.1.5以降).ng-ifはレンダリングを阻止することができます.したがって、他のDOMとデータバインディングは必要に応じて評価することができます.
<li ng-repeat="item in items">
    <p> {{ item.title }} </p>
    <button ng-click="item.showDetails = !item.showDetails">Show details</buttons>
    <div ng-if="item.showDetails">
        {{item.details}}
    </div>
</li>
    5.ng-mouseenter、ng-mouseleaveなどのコマンドは使用しないでください.
    内部コマンドを使用して、ng-mouseenterのように、AnglarJSはページを点滅させます.ブラウザのフレームレートは毎秒30フレーム以下です.jQueryを使ってアニメーションを作成し、マウスの浮遊効果で問題を解決できます.jQueryのLive関数にマウスイベントを入れることを確保します.
    6.フィルタリングに関するヒント:ng-showによって余分な要素を隠す
    長いリストでは、フィルタを使っても作業効率が低下します.フィルタリングごとに元のリストのサブリンクが作成されます.多くの場合、データが変化していないため、フィルタ結果も変化しません.データリストを事前フィルタリングし、状況に応じてビューに適用すると、処理時間が大幅に節約されます.
    n-repeatコマンドでフィルタを使用すると、各フィルタは元のリンクのサブセットに戻ります.AnglarJS DOMから余分な要素を除去します.呼び出しにより $destroy)は、同時に$scopeから削除されます.フィルタの入力が変わると、サブセットも変化します.要素は再リンクしなければなりません.またはdestroyを呼び出します.
    多くの場合、このようにすればいいですが、ユーザーがよくフィルタリングしたり、リストが巨大になったりすると、リンクや破壊が性能に影響を及ぼします.フィルタリングのスピードを上げるためには、ngshowやnghideコマンドが使えます.コントローラでフィルタリングを行い、各属性を追加します.この属性によって、ngshowをトリガします.結果としては、これらの要素のためだけにng-hを追加します.ideクラスは、サブリスト、$scope、およびDOMを除去する代わりに使用されます.
    ng-showをトリガする方法の一つは表現文法を使用することである.ng-showの値は式文法で決定される.以下の例を参照してください.
<input ng-model="query"></input>
<li ng-repeat="item in items" ng-show="([item.name] | filter:query).length">{{item.name}}</li><span style="font-size: 14px; line-height: 24px; font-family: Helvetica, Tahoma, Arial, sans-serif; white-space: normal;"></span>
        もう一つの方法はng-showのために属性を伝達し、単独のサブコントローラで計算することです.この方法はやや複雑ですが、より明確な方法です.
    7.フィルタのヒントについて:ディザ防止入力
    6点目に提示された持続的なフィルタリング問題を解決する別の方法は、ディザリング防止ユーザーの入力である.例えば、ユーザーが検索キーワードを入力すると、ユーザが入力を停止した後にフィルタが起動されます.このディザリング防止サービスを利用する良い解決策を参照してください.http://jsfiddle.net/Warspawn/6K7Kd/を選択します.ビューとコントローラに適用します.以下の通りです.を選択します
/* Controller */
// Watch the queryInput and debounce the filtering by 350 ms.
$scope.$watch('queryInput', function(newValue, oldValue) {
    if (newValue === oldValue) { return; }
    $debounce(applyQuery, 350);
});
var applyQuery = function() { 
    $scope.filter.query = $scope.query;
};

/* View */
<input ng-model="queryInput"/>
<li ng-repeat= item in items | filter:filter.query>{{ item.title }} </li>