38

の itemnames のリストに対して簡単な<input>検索フィルタを設定しましたAngularJS

私のリストは次のようになります。

var uniqueLists = {
    category1: ['item1', 'item2', 'item3' ... 'item180' ], // Real list contains ~180 items
    category2: ['itemA', 'itemB', 'itemC' ... 'itemZZZ' ], // Real list contains ~1080 items
    category3: ['otheritem1', 'otheritem2', 'otheritem3' ]  // Real list contains 6 items
  }

このリストを Angular で繰り返し処理し、結果を<ul>カテゴリごとに出力します。

<div ng-repeat="(key,val) in uniqueLists">
    <form ng-model="uniqueLists[index][0]">
        <input ng-model="searchFilter" type="text" />
            <ul>
                <li ng-repeat="value in val | filter: searchFilter">
                    <label>
                         <input type="checkbox" ng-model="selectedData[key][value]" />
                        {{value}}
                    </label>
                </li>
            </ul>
    </form>
</div>

わかりやすくするために、selectedData は次のようになります。

var selectedData = {category1: [item1:true], category2: [], category3: []); // if 'item1's checkbox is checked.

このリストは問題なく動作filterしていますが、非常に高速なコンピューターでも非常に遅れています。入力に文字を入力すると、リストが更新されるまでに 1 ~ 2 秒かかります。

これは、一度に約 1000 個のアイテムをフィルタリングしているためである可能性が高いことは承知していますが、他の場所でこれについての議論を見たことがありません.

フィルターのパフォーマンスを向上させる方法はありますか?

4

6 に答える 6

55

フィルター アプローチの主な問題は、変更のたびに dom が操作されるため、遅いのはフィルターではなく、その結果です。別の方法は、次のようなものを使用することです。

ng-show="([item] | filter:searchFilter).length > 0"

繰り返される要素について。

@OverZealous からいくつかのコードを借りて、以下を使用して動作を比較できます。


更新: Angular v1.2 ではtrack by構文が導入されました。このような問題にも役立ちます。要素に一意の属性がある場合、次を使用できます。

ng-repeat="item in items | filter:searchFilter track by item.id"

Whereitem.idはすべてのアイテムで一意である必要があります。track by最終リストに含まれなくなった dom-elements のみが削除され、他の要素は記憶されますtrack by一方、リスト全体が毎回再描画されない場合。要するに、dom の操作が大幅に減る = 再描画が速くなります。

于 2013-07-31T13:23:01.583 に答える
21

別の興味深い最適化は、特定の時間までモデルの変更を「トリガーしない」ことです。

これを検索入力フィールドに追加します: ng-model-options="{debounce: 500}"

これにより、ユーザーが 500 ミリ秒の間に入力を停止すると、フィルターがトリガーされます。

上記のフィドルを更新しました:

http://jsfiddle.net/CXBN4/14/

<input ng-model="searchFilter" type="text" ng-model-options="{debounce: 500}" />
于 2015-01-29T23:45:03.540 に答える
5

表示しているコード (の一部) をシミュレートするためのフィドルを作成しました。

私のコンピューターは高速ですが、超高速ではありませんが、許容できるほどうまく動作します。少し遅いですが、チェックボックスとの双方向バインディングを持つ非常に長いリストをフィルタリングしています。文字を入力するたびに、リスト全体をスキャンして項目を削除 (または追加) する必要があります。

これを解決するための最善の策は、この StackOverflowの回答に示されているように、ある種の単純なページネーションを追加することだと思います。

ここでは、ページネーションを含めるように例を変更しましたおそらく、 Next / Previousよりも優れたソリューションに投資したいと思うでしょうが、これは、すべてを一度に表示しない場合に結果が非常に高速になることを示しています。それでもリスト全体を検索しますが、レンダリングされたリストははるかに制限されています。

追加:

コントローラーのスコープにページング情報を追加します。

$scope.currentPage = 0;
$scope.pageSize = 20;
$scope.numberOfPages = function () {
    return Math.ceil($scope.items.length / $scope.pageSize);
}

特定のページから開始する新しいフィルターを作成します。

app.filter('startFrom', function () {
    return function (input, start, pageSize) {
        start = +start; //parse to int
        pageSize = +pageSize;
        while (start > input.length) {
            start -= pageSize;
        }
        if (start < 0) {
            start = 0;
        }
        return input.slice(start);
    };
});

ビューにフィルターを追加して、リストを制限します。

<li ng-repeat="value in items | filter:searchFilter |
        startFrom:currentPage*pageSize:pageSize | limitTo:pageSize">

ページネーション ボタンをページに追加します。

    <div>
        <button ng-disabled="currentPage == 0" ng-click="currentPage=currentPage-1">Previous</button> {{ currentPage+1 }}/{{ numberOfPages() }}
        <button ng-disabled="currentPage >= items.length/pageSize - 1" ng-click="currentPage=currentPage+1">Next</button>
    </div>
于 2013-07-31T12:56:46.580 に答える
4

入力でキーを押すたびに、すべてのウォッチ式を実行する必要があり、コードを見るとそれらがたくさんあります。アイテム名が不変の場合、たとえばhttps://github.com/abourget/abourget-angularを使用すると、次のように記述できます。

<label>
     <input type="checkbox" ng-model="selectedData[key][value]" />
     <span set-text='value'></span>
</label>

また、キーストロークごとに実行するウォッチ式が 1000 少なくなります。

さらに、最後のキーストロークから 500 ミリ秒後にフィルターがトリガーされるように、入力に対してある種のスロットリングを使用することもできます。

于 2013-07-31T12:53:38.677 に答える
4

「limitTo」フィルターを使用して、表示されるアイテムを制限することもできます。これにより、除外するモデル内に膨大な数のアイテムを保持できますが、DOM 内のすべてのアイテムを表示しようとしているわけではないため、それほど遅くはありません。

これは、以前の回答に基づいて変更された jsbin ですが、 limitTo フィルターが適用されています。

http://jsbin.com/IhOcaKo/1

于 2013-10-14T19:25:44.090 に答える