Angular OnPush策略下静态绑定是否执行差异检查?
Angular OnPush策略下静态@Input绑定的检测规则与性能对比
核心结论
- 静态绑定写法不会触发OnPush策略对应的@Input引用变更检测逻辑
- 两种绑定写法存在可感知的运行时性能差异,静态绑定的长期运行开销更低
两种写法的运行时本质差异
我们先把问题里的两个示例对应的运行时逻辑拆开说明:
- 静态绑定(示例A)
这种无方括号的写法,在Angular编译模板时会被处理为组件实例初始化阶段的一次性属性赋值:组件创建时直接把字符串字面量<sub-component myText="Hello World"></sub-component>Hello World赋值给myText输入属性,后续所有变更检测周期里,都不会对这个属性做任何求值、比对操作。
这里存在一个常见认知偏差:静态绑定不属于Angular的动态绑定范畴,OnPush策略针对@Input的引用检测逻辑,从设计上就只覆盖动态绑定的输入值,不会对一次性赋值的静态输入生效——毕竟这个值从赋值完成后就固定了,根本不存在“引用发生变化”的可能,自然也没有触发检测的前提。 - 动态绑定(示例B)
哪怕绑定的是硬编码的字符串字面量,只要加了方括号,Angular就会把它纳入动态绑定列表:每次执行变更检测时,都会对绑定表达式求值,将求值结果和上一次缓存的值做相等性比对——如果发现值(对基本类型来说是值相等性,对引用类型是引用相等性)和上一次不一样,就会按照OnPush策略把当前组件标记为需要脏检查的状态。<sub-component [myText]="'Hello World'"></sub-component>
注:因为示例B绑定的是固定硬编码字符串,每次求值的结果完全一致,所以永远不会真的触发脏标记,但这个比对动作本身是真实存在的,没有凭空消失。
两种写法的性能差异说明
- 首次渲染阶段:两者性能几乎无差异,都是完成一次相同的字符串属性赋值,不会产生可感知的开销区别。
- 长期运行阶段:性能差异体现在每次变更检测的固定成本上。动态绑定写法因为要被纳入检查队列,每次全局变更检测都会为这个绑定增加一次求值、值比对的动作;静态绑定因为是一次性赋值,从首次挂载完成后就完全脱离了变更检测流程,不会产生任何后续的检查开销。
- 日常开发提示:如果@Input要传入的是固定字符串字面量,优先使用静态绑定写法。写
[myText]="'Hello World'"不仅可读性差,还会平白给变更检测增加无意义的负担,属于怎么算都不划算的写法。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

