27

我有一个带有分页网格(两个嵌套的 ng-repeat)的 AngularJS 应用程序。一页大约有 25x40 个输入元素。刚开始绑定 1000 次,分页性能尚可。

但是随后页面的复杂性增加了:动态类、不同的上下文菜单、网格每个单元格的条件内容。并且估计有 6000 个绑定(每个输入元素 6 个),分页变得无法使用缓慢。

我的问题是:我通常如何处理 AngularJS 中的性能问题?显而易见的第一步是测量。但是 Chrome Profiler 的结果并没有告诉我太多,远不知道如何进行。

 Self      Total                           Function
-----------------------------------------------------------------
24 ms    2.79 s    angular.js:7997         Scope.$digest
 1 ms       1 ms   controllers.js:365      setViewportData
16 ms     692 ms   angular.js:13968        ngRepeatWatch
 8 ms      22 ms   angular.js:6439         extend.literal
 9 ms    1.22 s    angular.js:14268        ngSwitchWatchAction
16 ms      45 ms   angular.js:12436        ngModelWatch
 0        621 ms   angular-ui-4.0.js:264   initDateWidget
 0         13 ms   angular.js:12859        ngClassWatchAction
 0         70 ms   angular.js:14184        ngStyleWatchAction
 1 ms       5 ms   angular-ui-4.0.js:261   getOptions
 0         16 ms   angular.js:579          copy
 0          1 ms   angular.js:4558         interpolateFnWatchAction
 1 ms       2 ms   angular.js:5981         token.fn.extend.assign
 0         37 ms   angular.js:8151         Scope.$eval
 1 ms       1 ms   angular.js:6137         extend.constant
14 ms      16 ms   angular.js:651          equals
 1 ms       1 ms   angular.js:4939         $interpolate.fn

另外:“Object.observe()”是否有可能在未来加快速度(忽略“initDateWidget”,这显然是一个不同的话题)?

4

11 回答 11

28

你能做的最能加速你的 Angular 应用程序的事情就是尽可能减少那些绑定。一种方法是创建一个指令,使用 DOM 操作而不是使用 ng-repeats 为您构建表。这将减少您必须处理的整体手表数量,并使 $digest 更快。

我知道这样做很难看,但 Angular 并不是真的要设置 3000 多个绑定。因为它做了一个摘要并且它不是一个观察者模式,所以它真的减慢了设置这么多的东西。

您甚至可以使用混合方法,仍然使用 ng-repeat,但所有值都放置在 DOM 中,并通过自定义指令直接进行 DOM 操作,从而避免了所有绑定。

于 2013-03-26T17:39:18.250 回答
21

如果您还没有这样做,请安装 AngularJS Chrome 插件 Batarang,它将帮助您查明哪些绑定导致您不快。 https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk?hl=en

正如另一个答案所暗示的那样,您正在寻找的可能是您的表格的无限滚动设置的小案例,您绑定到的模型是您在屏幕上显示的子集。

ng-grid 组件实现了这一点,直接使用它或窃取技术可能值得一看。 http://angular-ui.github.com/ng-grid/

于 2013-03-29T21:35:12.477 回答
19

资源

这篇关于大型列表中 angularJS 性能的文章很好地概述了您用于性能调整的选项。

上面的答案(除了 Batarang 插件)也被提及。这只是该文章中提示的概述。

使用limitTo(分页)减少数据

更明显的解决方案之一是通过减少视图中的项目数量来减少绑定数量。数据的分页可以通过打开limitTo过滤器来完成ng-repeat

如何在巨大的数据集( angular.js )上提高 ngRepeat 的性能?那篇文章还链接了一个 jsbin 示例

还要确保不要使用内联方法来提供数据,因为这将在每个 $digest 上进行评估。

<li ng-repeat="item in filteredItems()"> // Bad idea, since very often evaluated.
<li ng-repeat="item in items"> // Way to go! 

使用 bindonce 删除绑定

另一个明显的解决方案是删除特定元素的绑定。当然,这意味着更新将不再反映在视图中。

bindonce解决方案不仅仅是删除 2 路绑定。基本上它会在绑定被删除之前等待值被绑定一次。最好自己读。检查bindonce 项目以获取详细信息。

在上面列出的文章中,还有关于使用 2 个列表的模式的信息。一个用于可视化,一个作为数据源。

使用 ng-grid

Ng-grid优点是它只渲染当前可见的元素。在http://angular-ui.github.io/ng-grid/阅读更多内容。

类似ng-if从 DOM 树中完全删除隐藏的元素,同时ng-show仅将它们保持在原位但隐藏。考虑到ng-if在再次显示时将放置原始元素的副本(原始元素是关键,而不是更改)。

过滤提示

这篇文章还有一些过滤列表的好技巧。

就像使用ng-show隐藏过滤掉的元素一样,因为这样就不必为数据创建子列表。

而另一种技术被称为“去抖用户输入”。最后一个选项是等待过滤,直到用户停止输入。包括一个 jsfiddle 示例

更多的

更多提示可以在链接的文章中找到。那里也列出了资源,所以这应该是一个很好的起点。我相信这里列出了最明显的一次和快速胜利。

另一个不错的文章是数据绑定在 AngularJS 中是如何工作的?

于 2014-02-12T11:34:03.533 回答
13

有点晚了,但也许这对你有用:

https://github.com/Pasvaz/bindence

您可以在那些不打算更改的绑定上使用它,因此 $digest 将不再处理它们。

于 2013-07-11T10:31:00.350 回答
7

在 Angular 1.3 及更高版本中,您可以使用 :: 绑定一次,无需使用其他 3 方 js

<li ng-repeat="item in :: items">

如果项目不会更改,这很好,因此您可以绑定它们一次

于 2014-11-23T09:03:04.227 回答
1

当数据网格组件中的侦听器数量超过 1000 时,我遇到了性能问题。

我解决了这个问题,使用了一个使用 react.js 构建我的视图的指令。该指令公开了一个更新功能。

每次数据发生变化(在控制器中),更新函数都会触发指令,然后 react.js 引擎高效地进行渲染。

我知道在 Angular 项目中使用第二个主要框架的开销很大,这不是真正的数据绑定魔法。但它的工作速度要快得多。

最终我停止使用 angular.js 并转向 react.js + FLUX 。我认为它更好,但我知道从角度转变并不容易,但它是值得的。

使用 react.js 的 Angular 指令

于 2015-04-02T13:23:25.260 回答
0

限制手表的数量通常会有很长的路要走。以下是对减少手表数量有效的技术摘要

http://www.syntaxsuccess.com/viewarticle/547a8ba2c26c307c614c715e

于 2015-02-05T22:06:34.263 回答
0

我在使用大数据的 ng-grid 时遇到了性能问题,通过用Angular Grid替换它来解决。它网站上的演示显示它可以轻松管理 100,000 行。

于 2015-04-03T22:54:55.083 回答
0

我已经为此苦苦挣扎了几个星期。我发现有两件事有很大的不同:

(i) 一次性绑定:尽可能使用一次性绑定;(ii) DEBOUNCE:对于不需要我立即传播但可以等待 250 毫秒的输入,设置去抖动设置。这对我的大型 ng-repeat 表产生了难以置信的影响。我无法强调去抖动设置的有效性。(见这里:https ://docs.angularjs.org/api/ng/directive/ngModelOptions )

于 2015-04-04T19:22:41.270 回答
0

您还可以通过禁用调试数据来提高性能

于 2017-10-20T11:32:32.207 回答
0

bject.observe() 是一种为浏览器带来真正数据绑定的提议机制。它公开了一种机制来观察对象和数组的变化,通知其他人这些对象发生的变化。

<!DOCTYPE html>
<html>
<head>
<base target="_blank">
<title>Object.observe()</title>

<link rel="stylesheet" href="../css/main.css" />

</head>

<body>

<div id="container">

  <h1><a href="https://shailendrapathakbits.wordpress.com/" title="code_lab_by_shail ">code_lab_by_shail</a> Object.observe()</h1>

    <p>An object <code>o</code> is created and <code>Object.observe()</code> is called on it.</p>

  <p>Three changes are made to <code>o</code> and <code>Object.observe()</code> records these changes as shown below.</p>

  <p>Use the console to find out what happens if you make further changes to <code>o</code>: it's defined in global scope.</p>

  <p>Call <code>Object.unobserve(o, observer)</code> to stop observing changes.</p>

  <p id="data" style="font-size: 14px;"></p>

  <script src="js/main.js"></script>

  <a href="https://github.com/shailendra9/objectobserver/blob/master/index.html" title="View source for this page on GitHub" id="viewSource">View source on GitHub</a>

</div>

<script src="../js/lib/ga.js"></script>

</body>
</html>
于 2015-08-18T05:48:20.517 回答