【问题标题】:How to speed up an AngularJS Application?如何加速 AngularJS 应用程序?
【发布时间】:2017-10-20 19:32:32
【问题描述】:

我有一个带有分页网格的 AngularJS 应用程序(两个嵌套的 ng-repeat)。一页大约有 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',这显然是另一个话题)?

【问题讨论】:

标签: angularjs performance


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 多么棒的工具!谢谢,谢谢,谢谢!这应该安装在每台开发人员计算机上;-)
    • 不错的工具,但它仍然显示 ngModelWatch 占用了总时间的 91.9%,所以这种方式很难准确定位,也许我用错了方法
    【解决方案3】:

    资源

    This post about angularJS performance on large lists 很好地概述了您用于性能调整的选项。

    其中还提到了以上答案(Batarang 插件除外)。这只是该文章中提示的概述。

    使用limitTo(分页)减少数据

    更明显的解决方案之一是通过减少视图中的项目数量来减少绑定数量。可以使用ng-repeat 上的limitTo 过滤器对数据进行分页。

    How to improve performance of ngRepeat over a huge dataset (angular.js)? 的示例该文章还链接了a jsbin example

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

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

    使用 bindonce 删除绑定

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

    bindence 解决方案不仅仅是删除 2 路绑定。基本上它会在绑定被删除之前等待值被绑定一次。最好自己读。详情请查看the bindonce project

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

    使用 ng-grid

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

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

    过滤提示

    这篇文章还提供了一些过滤列表的重要技巧。

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

    还有另一种称为“去抖动用户输入”的技术。最后一个选项是等待过滤,直到用户停止输入。包括a jsfiddle example

    更多

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

    另一个不错的文章是How does data binding work in AngularJS?

    【讨论】:

      【解决方案4】:

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

      https://github.com/Pasvaz/bindonce

      你可以在那些不打算改变的绑定上使用它,这样 $digest 就不会再处理它们了。

      【讨论】:

        【解决方案5】:

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

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

        如果项目不会改变这样你就可以绑定它们一次,这很好

        【讨论】:

          【解决方案6】:

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

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

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

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

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

          Angular directive that uses react.js

          【讨论】:

            【解决方案7】:

            限制手表的数量通常可以起到很大的作用。以下是对减少手表数量有效的技巧的总结

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

            【讨论】:

              【解决方案8】:

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

              【讨论】:

                【解决方案9】:

                我已经为此苦苦挣扎了几个星期。我发现有两件事产生了重大影响:

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

                【讨论】:

                  【解决方案10】:

                  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>
                  

                  【讨论】:

                    【解决方案11】:

                    您还可以通过Disabling Debug Data 提高总体性能

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-05-16
                      • 2017-01-25
                      • 1970-01-01
                      • 1970-01-01
                      • 2013-02-18
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多