如何在庞大的数据集 (angular.js) 上提高 ngRepeat 的性能?

IT技术 javascript angularjs angularjs-ng-repeat
2021-02-10 07:46:14

我有一个包含数千行的庞大数据集,每行大约有 10 个字段,大约有 2MB 的数据。我需要在浏览器中显示它。最直接的方法(获取数据,放入$scope,让其ng-repeat=""完成工作)工作正常,但是当它开始将节点插入 DOM 时,它会冻结浏览器大约半分钟。我应该如何解决这个问题?

一种选择是$scope增量地追加行并等待ngRepeat完成将一个块插入到 DOM 中,然后再移动到下一个。但是 AFAIK ngRepeat 在完成“重复”后不会返回报告,所以它会很丑。

另一种选择是将服务器上的数据拆分成页面并在多个请求中获取它们,但这更难看。

我查看了 Angular 文档以寻找类似的东西ng-repeat="data in dataset" ng-repeat-steps="500",但一无所获。我对 Angular 的方式还很陌生,所以我可能完全忽略了这一点。这方面的最佳做法是什么?

6个回答

我同意@AndreM96 的观点,即最好的方法是只显示有限数量的行,更快更好的用户体验,这可以通过分页或无限滚动来完成。

使用limitTo过滤器,Angular 的无限滚动非常简单您只需要设置初始限制,当用户要求更多数据时(为简单起见,我使用按钮)您增加限制。

<table>
    <tr ng-repeat="d in data | limitTo:totalDisplayed"><td>{{d}}</td></tr>
</table>
<button class="btn" ng-click="loadMore()">Load more</button>

//the controller
$scope.totalDisplayed = 20;

$scope.loadMore = function () {
  $scope.totalDisplayed += 20;  
};

$scope.data = data;

这是一个JsBin

这种方法对于手机来说可能是一个问题,因为它们通常在滚动大量数据时会滞后,所以在这种情况下,我认为分页更适合。

为此,您将需要 limitTo 过滤器和一个自定义过滤器来定义所显示数据的起点。

这是一个带有分页JSBin

如果用户按下 loadmore 10 次,每次按下增加 100 个项目,这如何提高性能?
2021-03-28 07:46:14
@Sumit limitTo 将应用于 ng-repeat 范围,因此结果将是一个将传递给 ng-repeat 的新数组,您的数据数组仍然相同,您仍然可以搜索所有内容。
2021-03-31 07:46:14
不错的选择!!!如果我必须显示所有项目,您知道可以使用的任何方法。任何加载标志或一个接一个插入 DOM 之类的?
2021-04-01 07:46:14
您的意思是在获取数据时显示“正在加载...”或其他内容吗?
2021-04-05 07:46:14
@hariszaman 我同意。这不会提高性能。它只是延迟了糟糕的表现。无限滚动会给你带来麻烦,除非你正在虚拟化它(ui-grid 就是这样做的)。
2021-04-10 07:46:14

Ionic 的 collectionRepeat 指令和其他类似实现的方法体现了克服大型数据集这些挑战的最热门 - 并且可以说是最可扩展的 - 方法一个花哨的术语是“遮挡剔除”,但您可以将其总结为:不要将渲染的 DOM 元素的数量限制为任意(但仍然很高)的分页数,如 50、100、500...相反,仅限于用户可以看到的尽可能多的元素

如果您执行诸如通常所说的“无限滚动”之类的操作,您会在一定程度上减少初始DOM 计数,但在几次刷新后它会迅速膨胀,因为所有这些新元素都只是添加到底部。滚动开始爬行,因为滚动与元素计数有关。没有什么是无限的。

然而,该collectionRepeat方法是仅使用适合视口的尽可能多的元素,然后回收它们当一个元素旋转出视图时,它与渲染树分离,重新填充列表中新项目的数据,然后重新附加到列表另一端的渲染树。这是人类已知的从 DOM 中获取新信息的最快方式,利用有限的现有元素集,而不是传统的创建/销毁...创建/销毁循环。使用这种方法,您可以真正实现无限滚动。

请注意,您不必使用 Ionic 来使用 /hack/adaptcollectionRepeat或任何其他类似的工具。这就是为什么他们称之为开源。:-)(也就是说,Ionic 团队正在做一些非常巧妙的事情,值得您关注。)


在 React 中做一些非常相似的事情至少有一个很好的例子只是不是回收具有更新内容的元素,您只是选择不在视图中呈现树中的任何内容。它在 5000 个项目上非常快,尽管它们非常简单的 POC 实现允许有点闪烁......


另外……为了回应其他一些帖子track by,即使使用较小的数据集,使用也是非常有帮助的。认为它是强制性的。

Ionic 团队的绝妙创意。我想知道这是否来自本地视图的呈现方式?
2021-03-18 07:46:14
例如,iOS 中的 UITableView 使用相同的方法来呈现大数据集。我认为这是许多原生视图中常用的方法。
2021-04-05 07:46:14

我建议看这个:

优化 AngularJS:1200ms 到 35ms

他们通过在 4 个部分优化 ng-repeat 来制定新指令:

优化#1:缓存DOM元素

优化#2:聚合观察者

优化#3:推迟元素创建

优化#4:绕过隐藏元素的观察者

该项目在 github 上:

用法:

1- 在您的单页应用程序中包含这些文件:

  • 核心.js
  • scalyr.js
  • slyEvaluate.js
  • slyRepeat.js

2- 添加module依赖:

var app = angular.module("app", ['sly']);

3-替换ng-repeat

<tr sly-repeat="m in rows"> .....<tr>

请享用!

我尝试使用 Scalyr,但过滤器不起作用。<tr sly-repeat="main.customers 中的选项 | 过滤器:search_input | limitTo:20">
2021-03-23 07:46:14
我认为这个 scalyr.js 已经包含其他文件。因为是构建脚本的结果。
2021-03-30 07:46:14
包含所有四个 js 文件并使用,sly-repeat但没有任何帮助,结果仍然很慢,浏览器滞后也有违规行为[Violation] 'setTimeout' handler took 54ms[Violation] 'scroll' handler took 1298ms
2021-04-02 07:46:14
这是非常有帮助的。我在 AngularJS 1.6 应用程序上使用它,客户端希望看到大量数据单元格(通常我设计具有分页/减少数据元素的表单,但客户端需要一次比较大量数据)。到目前为止,由于这个库,单元格的网格已经从无法使用变为完美无缺。但是这个库是在 AngularJS 1.2 天写的,所以我会仔细测试以寻找问题。
2021-04-09 07:46:14
据我目前所知,gatedScope.js 文件(323 行)是唯一需要验证才能在最新版本的 AngularJS 上运行的文件。这pull请求是显着的:github.com/karser/angular/commit/...它更新签名 rootScope.$new。
2021-04-09 07:46:14

除了上述所有提示(例如跟踪和较小的循环)之外,这个提示也对我有很大帮助

<span ng-bind="::stock.name"></span>

这段代码会在加载后打印名称,然后停止观看。同样,对于 ng-repeat,它可以用作

<div ng-repeat="stock in ::ctrl.stocks">{{::stock.name}}</div>

但是它只适用于 AngularJS 1.3 及更高版本。来自 http://www.befundoo.com/blog/optimizing-ng-repeat-in-angularjs/

你需要::重复和表达吗?文档另有说法,但我不确定如何测试它是否有效。docs.angularjs.org/guide/expression
2021-04-03 07:46:14
::是多余的。ng-bind 用于实现单向数据绑定。
2021-04-04 07:46:14

您可以使用“track by”来提高性能:

<div ng-repeat="a in arr track by a.trackingKey">

比...快:

<div ng-repeat="a in arr">

参考:https : //www.airpair.com/angularjs/posts/angularjs-performance-large-applications

这仅在 ng-repeat 中的数据发生变化时才有用。对于初始加载,它可能不会带来性能改进。
2021-03-26 07:46:14
使用 track by 您不会在每次获得新数据时从头开始跟踪数组元素。因此,这提高了性能。
2021-04-05 07:46:14
这对性能没有真正的帮助。参见jsperf.com/ng-repeat-vs-ng-repeat-with-trace-by-id
2021-04-10 07:46:14