AngularJS 'ng-filter' 在约 1000 个元素的数组上非常慢
Posted
技术标签:
【中文标题】AngularJS \'ng-filter\' 在约 1000 个元素的数组上非常慢【英文标题】:AngularJS 'ng-filter' is very slow on array of ~1000 elementsAngularJS 'ng-filter' 在约 1000 个元素的数组上非常慢 【发布时间】:2013-07-31 21:49:24 【问题描述】:我为AngularJS
中的项目名称列表设置了一个简单的<input>
搜索过滤器。
我的列表如下所示:
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 个项目,但我没有在其他地方看到任何关于此的讨论。
有什么方法可以让过滤器获得更好的性能?
【问题讨论】:
在这种情况下,用你的代码做一个 jsfiddle 真的很有帮助。我也可以想象在循环中有一个循环然后过滤是相当多的,你也在第一个循环中创建一个表单。一个 jsffidle 真的会帮助我们帮助你 ;) 【参考方案1】:过滤器方法的主要问题是,每次更改时都会操纵 dom,因此变慢的不是过滤器而是后果。另一种方法是使用类似的东西:
ng-show="([item] | filter:searchFilter).length > 0"
在重复的元素上。
从@OverZealous 借一些代码,你可以使用以下来比较行为:
过滤器:http://jsbin.com/fuwadanu/1/ ng 显示:http://jsbin.com/xajehulo/1/更新:Angular v1.2 出现了track by
语法。这也有助于解决此类问题。如果元素有一些独特的属性,可以使用:
ng-repeat="item in items | filter:searchFilter track by item.id"
item.id
在所有项目中必须是唯一的。对于track by
,只有那些不再出现在最终列表中的 dom 元素将被删除,其他元素将被记住。而没有track by
,整个列表每次都会重绘。简而言之:更少的 dom 操作 = 更快的重绘。
【讨论】:
这应该是答案。这效果太好了,我简直不敢相信! ng-show 的速度提升确实令人印象深刻。谢谢你的解释 几年后回来,不敢相信我忘了标记答案! 我用 50 000 项和 1. 和 3. 解决方案尝试了您的代码,但解决方案会阻止 chrome,但是使用 ng-show 的第二个解决方案非常快并且在半秒内执行ng-repeat="item in items | filter:searchFilter track by item.id"
这导致性能提升正好为 0。我的数据已经是对象形式,具有唯一值,添加 track by depot.val
完全没有区别。我错过了什么吗?【参考方案2】:
另一个有趣的优化是在特定时间之前“不触发”模型更改。
将此添加到您的搜索输入字段:ng-model-options="debounce: 500"
如果用户在 500 毫秒内停止输入,这将触发过滤器。
我更新了上面的小提琴:
http://jsfiddle.net/CXBN4/14/
<input ng-model="searchFilter" type="text" ng-model-options="debounce: 500" />
【讨论】:
如果你想将它与 ng-change 结合使用,请看这里:***.com/questions/26446681/angular-ng-change-delay【参考方案3】:I created a fiddle to simulate (part of) the code you are showing.
在我的电脑上,虽然速度很快但不是超快,但运行良好。它有点慢,但它正在过滤一个过长的列表,该列表与复选框具有双向绑定。每次键入字母时,都必须扫描整个列表并删除(或添加)项目。
我认为解决此问题的最佳选择是添加某种简单的分页,如this *** 答案所示。
Here I've modified my example to include pagination。您可能希望投资于一个比下一个/上一个更好的解决方案,但这向您展示了如果您不一次显示所有内容,结果是如何非常快的。它仍然搜索整个列表,但呈现的列表受到更多限制。
补充:
在控制器的作用域中添加分页信息:
$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>
【讨论】:
【参考方案4】:每次输入时都需要执行所有监视表达式,并查看您的代码,您有很多它们。 如果项目名称是不可变的,您可以使用例如https://github.com/abourget/abourget-angular,它允许您编写:
<label>
<input type="checkbox" ng-model="selectedData[key][value]" />
<span set-text='value'></span>
</label>
而且每次击键时要执行的监视表达式减少了 1000 个。
此外,您可以对输入使用某种限制,以便在最后一次击键后 500 毫秒后触发过滤器。
【讨论】:
【参考方案5】:您还可以使用“limitTo”过滤器限制将要显示的项目。这允许您在模型中仍然有大量要过滤掉的项目,但它不会那么慢,因为您没有尝试显示 DOM 中的所有项目。
这是一个基于早期答案的修改 jsbin,但应用了 limitTo 过滤器:
http://jsbin.com/IhOcaKo/1
【讨论】:
【参考方案6】:没有适合我的解决方案:(
最后我以这种方式解决了这个问题:
<li ng-repeat="value in val | filter: searchFilter | limitTo:200">
试试就解决了... :)
【讨论】:
以上是关于AngularJS 'ng-filter' 在约 1000 个元素的数组上非常慢的主要内容,如果未能解决你的问题,请参考以下文章
尽管 ping 通,Websocket 在约 2 小时后获得连接壁橱
Pushsharp - APNS 服务在约 12 小时后消耗内存并死亡
LSTM Numpy、损失、细胞状态、梯度、权重在约 250 次训练迭代后变为 NAN