Angular 10三类数据绑定场景下的DOM更新性能对比问题
问题1:三种场景哪种更新DOM性能更高?
默认使用ChangeDetectionStrategy.Default变更检测策略的前提下,三种场景更新DOM的性能几乎没有差异。
Angular的变更检测执行逻辑是:先对模板中所有绑定的表达式逐个求值,和上一次缓存的值做对比,只有值发生变化的绑定才会触发对应的DOM更新。三种场景如果都只修改a属性/变量的值,最终都只会更新a对应的DOM节点,其他未变化的绑定不会触发DOM操作。
如果组件开启了ChangeDetectionStrategy.OnPush策略,场景III性能最优:OnPush策略会通过输入属性的引用变化判断是否需要执行变更检测,场景III替换整个对象的操作会直接触发变更检测;场景II的对象原地更新不会改变引用,默认无法触发OnPush组件的变更检测,需要额外调用ChangeDetectorRef.markForCheck(),会多出额外开销;场景I如果是多个独立输入属性,OnPush需要逐个校验所有输入属性的变化,对比单个对象引用的场景III开销更高。
问题2:场景I仅修改a的值时,是否只会重新渲染受a影响的HTML部分?
是。
Angular的变更检测是细粒度到每个独立绑定的,只有绑定的表达式求值结果和上一次不一致时,才会更新对应绑定的DOM节点。b、c等其他变量的值没有变化,对应的绑定完全不会触发DOM操作,也不会重新渲染关联的HTML部分。
问题3:场景III仅更新属性a时,是否会导致所有依赖obj的DOM部分重新渲染?
不会。
虽然obj的整体引用发生了变化,但Angular对obj.a、obj.b、obj.c这类绑定是分别独立求值对比的:obj.a求值结果变化会更新对应DOM,obj.b、obj.c的求值结果和之前一致,对应的DOM不会有任何更新操作。
唯一的例外是你把整个obj作为输入属性传递给了开启OnPush策略的子组件,此时子组件会因为输入属性引用变化触发自身的变更检测,但只要子组件内部绑定的obj属性没有变化,也不会产生多余的DOM更新。
内容的提问来源于stack exchange,提问作者Rahul R Badenkal

