【问题标题】:Angular view performance related to ng-app/ng-controller placement in DOM与 DOM 中的 ng-app/ng-controller 放置相关的 Angular 视图性能
【发布时间】:2015-09-05 06:27:23
【问题描述】:

我想知道如果我将 ng-appng-controller 属性位置从 body 更改为一些更小的内页块元素,是否可以在我的 Angular 应用程序(特别是视图处理)中获得任何显着的性能差异DOM 子树?

假设我有一个非常长的页面,其中包含大量内容,但其中只有一部分是 Angular 驱动的。其他一切都是服务器生成的,这意味着它在客户端 PoV 中有些静态。

ng-app/ng-controller 仅放在Angular 实际执行的那个子节点上会更好,还是如果我将它们放在这个很长页面的body 元素上会不会更好?

Angular 是只处理定义了 ng-app/ng-controller 的子 DOM 的视图,还是处理整个 DOM?

有没有关于这个甚至 Angular 文档的证据?

【问题讨论】:

    标签: angularjs performance dom ng-controller ng-app


    【解决方案1】:

    Official docs 表示只有包装到 ng-app 指令中的部分被编译。

    如果找到 ng-app 指令,那么 Angular 将:

    • 加载与指令关联的模块。
    • 创建应用程序
    • injector 编译 DOM,将 ng-app 指令视为 汇编。这允许你告诉它只处理一部分 DOM 作为 Angular 应用程序。

    这是意料之中的,因为 Angular 允许多个 Angular 模块控制一个页面的独立部分(需要手动引导,正如 Josiah Keller 在 cmets 中指出的那样)。而且它们的作用域不会干扰。

    但是,添加额外的静态 html(不是角度限制)只会在引导时影响性能。是的,Angular 必须在引导程序中编译所有这些元素,以了解它是否应该稍后处理它们。
    但运行时性能主要受$watchs 的影响。创建它们的隐式形式是进行绑定。因此,您拥有的绑定越多,每个$digest 循环所需的时间就越长。并给人一种慢应用的普遍感觉。对于现代浏览器/CPU,我已经达到了 2k 手表的合理阈值

    【讨论】:

    • “Angular 允许在一页中有多个 ng-app 指令”——我认为这并不完全正确。 The docs for ngApp 说“每个 HTML 文档只能自动引导一个 AngularJS 应用程序。在文档中找到的第一个 ngApp 将用于定义根元素以自动引导为应用程序。在 HTML 文档中运行多个应用程序您必须使用 angular.bootstrap 手动引导它们。”
    • @JosiahKeller 你说得对,我会更新措辞。我的意思是 DOM 的不同部分可以由不同的 Angular 模块控制
    【解决方案2】:

    ng-app 实际上只是指定了 Angular 调用 angular.bootstrap 的根元素。 bootstrap 启动一个“编译”过程,也就是说它遍历根的子树中的每个 DOM 元素,并从中收集指令并链接它们。

    在那里,您可以看到将应用程序限制在 DOM 的较小子树中的好处:

    1. 编译过程稍快
    2. 编译的指令更少(例如,不应该成为应用一部分的<input> 元素不会被编译/链接)。

    要记住的是,$digest 循环是性能问题/优化机会的重要来源——即$watchers 的数量以及"$watchers" 的速度。

    【讨论】:

    • 好的。因此,考虑到 ng-app 中的整个 DOM 中的绑定数量或 ng-app 中的部分 DOM 中的绑定数量应该不会在 $digest 中产生差异,因为两者都应用了相同数量(和相同)的绑定?
    • @RobertKoritnik, 对... 可能被“错误”编译的指令 - 像 input 指令,不要添加任何观察者或监听者而不应用 ngModel,所以非Angular HTML 不会有这些。
    【解决方案3】:

    理论上/潜在地?是的,正如 New Dev 所提到的,bootstrap 函数将有一个更大的 DOM 来运行 compile,这比编译一个较小的树需要更长的时间。 p>

    实际上?可能不会。但最好的办法是对自己的页面进行基准测试。

    作为实验,您可以尝试以下方法。我生成了一个简单的随机 DOM 并将其注入到带有 console.time 的 JSFiddle 中,从脚本加载开始,到控制器准备就绪时结束。在一个更大的 5000 节点树旁边(作为兄弟)有一个小的子树。

    这是包裹整个身体的小提琴:http://jsfiddle.net/gruagq8d/

    这是只使用小子集的小提琴:http://jsfiddle.net/h0hod2j8/

    对我来说,反复运行这些小提琴中的任何一个都会在大约 260 毫秒内收敛。

    我也尝试在真实的网页源上运行类似的代码,例如 StackOverflow 本身,并发现了相同的结果(但是我没有发布任何这些,因为未经许可将其他人的真实页面发布到 JSFiddle 感觉不合适) - 你可以自己尝试一下。

    诚然,这并没有遵循很好的基准测试方法,但如果包装大量额外的 DOM 节点会导致显着不同的性能,我仍然希望这些中至少有一些差异。

    我认为额外的编译时间不是问题;对于小型 DOM,它显然很快,而对于大型 DOM,与您的浏览器首先构建 DOM 所花费的时间相比,它非常重要。

    总而言之,如前所述,您最好的选择是尝试在您自己的页面上运行类似的基准测试。

    编辑:修改相同的基准来测试摘要周期表明它们也没有显着差异:

    最小包装:http://jsfiddle.net/fsyfn1ee/

    包装整个 DOM:http://jsfiddle.net/04tdwxhp/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-17
      • 1970-01-01
      • 2017-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-20
      • 1970-01-01
      相关资源
      最近更新 更多