property number array angularjs angularjs-ng-repeat angularjs-filter

number - AngularJS ''ng-filter'' es muy lento en la matriz de ~ 1000 elementos



angularjs number format comma (6)

Tengo un filtro de búsqueda <input> simple configurado para una lista de nombres de elementos en AngularJS .

Mi lista se ve así:

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 }

Paso iterativamente por esta lista en Angular e imprimo los resultados en un <ul> para cada categoría.

<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>

Para mayor claridad, selectedData se ve así:

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

Esta lista está funcionando bien, aunque el filter es bastante lento, incluso en mi computadora bastante rápida. Escribir una letra en la entrada lleva 1-2 segundos para que la lista se actualice.

Soy consciente de que esto es probable porque estoy filtrando alrededor de 1000 artículos a la vez, pero no he visto ninguna discusión sobre esto en otro lugar.

¿Hay alguna manera de obtener un mejor rendimiento fuera del filtro?


Cada vez que presionas la tecla Intro todas las expresiones de reloj deben ser ejecutadas y al mirar tu código tienes muchas de ellas. Si los nombres de los elementos son inmutables, puede usar, por ejemplo, https://github.com/abourget/abourget-angular que le permite escribir:

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

Y tiene 1000 menos expresiones de reloj para ejecutar en cada golpe de teclado.

Además, puede usar algún tipo de regulación en la entrada para que el filtro se active después de 500 ms de la última pulsación de tecla.


El principal problema con el enfoque de filtro es que en cada cambio se manipula el dom, por lo que no es el filtro el que es lento, sino las consecuencias. Una alternativa es usar algo como:

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

en el elemento repetido

Prestando un código de @OverZealous, puede usar lo siguiente para comparar el comportamiento:

Actualización : con Angular v1.2 llegó la track by sintaxis. Lo cual también ayuda con tales problemas. Siempre que los elementos tengan algún atributo único, uno puede usar:

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

Donde item.id tiene que ser único en todos los artículos. Con la track by solo aquellos elementos dom que se eliminarán, que ya no están en la lista final, otros serán recordados . Mientras que sin track by toda la lista se vuelve a dibujar cada vez. En resumen: mucha menos manipulación dom = redibujar más rápido.


No hay soluciones que funcionen para mí :(

Finalmente SOLUCIONÉ el problema de esta manera simplemente:

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

solo pruébalo y soluciona ... :)


Otra optimización interesante es "no activar" el cambio de modelo hasta cierto tiempo.

Agregando esto a su campo de entrada de búsqueda: ng-model-options = "{rebote: 500}"

Esto activará el filtro si el usuario deja de escribir durante 500 ms.

Actualicé el violín anterior:

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

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


También podría limitar los elementos que se mostrarán utilizando un filtro "limitTo". Esto le permite tener una gran cantidad de elementos en su modelo que está filtrando, pero no será tan lento porque no está tratando de mostrar TODOS los elementos en el DOM.

Aquí hay un jsbin modificado basado en respuestas anteriores, pero con el filtro de límite aplicado:

http://jsbin.com/IhOcaKo/1


Creé un violín para simular (parte de) el código que estás mostrando.

En mi computadora, que es rápida pero no muy rápida, funciona aceptablemente bien. Es un poco lento, pero está filtrando una lista demasiado larga que tiene un enlace bidireccional con las casillas de verificación. Cada vez que escribe una letra, la lista completa debe escanearse y los elementos deben eliminarse (o agregarse).

Creo que su mejor apuesta para resolver esto es agregar algún tipo de paginación simple, como se muestra en esta respuesta de .

Aquí modifiqué mi ejemplo para incluir la paginación . Es probable que desee invertir en una solución mejor que solo Siguiente / Anterior , pero esto le muestra cómo el resultado puede ser extremadamente rápido si no muestra todo de una vez. Aún busca en toda la lista, pero la lista procesada es mucho más limitada.

Las adiciones:

Agregue información de paginación al alcance en el controlador:

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

Crea un nuevo filtro para comenzar desde una página específica:

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); }; });

Agregue filtros a la vista para limitar la lista:

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

Agregue botones de paginación a la página:

<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>