sourcetip

AngularJS의 'ng-filter'는 최대 1000개의 요소 배열에서 매우 느립니다.

fileupload 2023. 2. 9. 22:27
반응형

AngularJS의 'ng-filter'는 최대 1000개의 요소 배열에서 매우 느립니다.

심플한 게 있어요<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>

알기 쉽게 하기 위해 selected Data는 다음과 같습니다.

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

이 리스트는 정상적으로 동작하고 있습니다만,filter꽤 빠른 컴퓨터에서도 꽤 느려요.입력에 문자를 입력하면 목록이 갱신되는 데 1~2초가 걸립니다.

한 번에 1000개 정도의 아이템을 걸러내고 있기 때문에 그럴 가능성이 있다는 것은 알고 있습니다만, 다른 곳에서는 이에 대해 논의한 적이 없습니다.

필터에서 더 나은 성능을 얻을 수 있는 방법이 있을까요?

필터 접근법의 주요 문제는 매번 변경될 때마다 돔이 조작된다는 것입니다. 따라서 느린 것은 필터가 아니라 결과입니다.다른 방법으로는 다음과 같은 것을 사용할 수 있습니다.

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

반복 요소 위에 있습니다.

@OverZealous에서 일부 코드를 대여하면 다음 명령을 사용하여 동작을 비교할 수 있습니다.


업데이트: Angular v1.2에서는track by구문을 사용합니다.그런 문제에도 도움이 됩니다.요소에 몇 가지 고유한 속성이 있는 경우 다음을 사용할 수 있습니다.

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

어디에item.id모든 항목에서 고유해야 합니다.와 함께track by최종 리스트에서 제외된 돔 리스트만 삭제되고 나머지는 기억됩니다.반면, 없는 경우track by목록 전체가 매번 다시 그려집니다.요컨대 돔 조작은 훨씬 적어 = 재추첨이 빨라집니다.

  • 추적 기준: http://jsbin.com/dufasego/1/

또 다른 흥미로운 최적화는 특정 시간까지 모델 변경을 '트리거'하지 않는 것입니다.

검색 입력 필드에 추가: ng-model-param="{carnounce: 500}"

사용자가 500ms 동안 입력을 중지하면 필터가 트리거됩니다.

위의 바이올린을 업데이트했습니다.

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

<input ng-model="searchFilter" type="text" ng-model-options="{debounce: 500}" />

당신이 보여주고 있는 코드를 시뮬레이트하기 위해 바이올린을 만들었습니다.

내 컴퓨터에서는, 속도는 빠르지만, 매우 빠르지 않고, 정상적으로 동작합니다.조금 느리지만 체크박스와 양방향 바인딩이 있는 지나치게 긴 목록을 필터링하고 있습니다.문자를 입력할 때마다 전체 목록을 스캔하고 항목을 제거(또는 추가)해야 합니다.

문제를 해결하기 위한 최선의 방법은 이 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>

입력 키를 누를 때마다 모든 워치 식을 실행해야 하며 코드를 보면 많은 워치 식을 볼 수 있습니다.아이템명이 불변하는 경우는, 예를 들면 https://github.com/abourget/abourget-angular 를 사용해 다음의 내용을 기입할 수 있습니다.

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

각 키를 누를 때마다 실행하는 워치 표현은 1000개 줄어듭니다.

또한 입력에 대한 조절 기능을 사용하여 마지막 키 입력으로부터 500ms 후에 트리거를 필터링할 수 있습니다.

또한 "limitTo" 필터를 사용하여 표시되는 항목을 제한할 수도 있습니다.이렇게 하면 모델에 필터링 중인 항목이 많이 남아 있지만 DOM의 모든 항목을 표시하려는 것은 아니기 때문에 속도가 느리지는 않습니다.

다음은 이전 응답을 기반으로 수정된 jsbin입니다. 단, limitTo 필터가 적용되었습니다.

http://jsbin.com/IhOcaKo/1

어떤 솔루션도 효과가 없습니다.

마지막으로 다음과 같이 간단하게 문제를 해결했습니다.

<li ng-repeat="value in val | filter: searchFilter | limitTo:200">

한번 시도해보고 해결하면...:)

언급URL : https://stackoverflow.com/questions/17969207/angularjs-ng-filter-is-very-slow-on-array-of-1000-elements

반응형