在Angular框架的进化中,Ivy渲染引擎的引入成为了关键转折点,它带来了性能提升、维护性和代码可读性的显著改善。本文将通过可视化的方式,深入探讨Ivy在变更检测机制上的运作,同时,我们也将从零构建基于Ivy的demo应用,以直观展示其工作原理。首先,为了更好地理解本文内容,我们提供了一个在线demo,它展示了如何在不同的生命周期区块内触发变更检测流程。只需要在Sub-Child组件的输入框中输入文本,即可体验到变更检测的实时响应。在Angular中,视图(View)是底层抽象的核心,它用于描述模板结构,包含了用于反射模板的数据。以ChildComponent为例,其视图结构包含了特定的模板。在传统渲染引擎中,视图定义通过工厂创建节点,并将节点存储在视图定义的nodes数组中。而在Ivy中,使用ngComponentDef.template函数创建LNodes,并将其存储在data数组中。此外,data数组还包括绑定信息,这些信息按照模板中出现的顺序存储,起始位置为bindingStateIndex参数的值。要获取ChildComponent的view实例,可以通过ComponentInstance.__ngHostLNode__属性或使用注入ChangeDetectorRef的方式。通过这种方法,Angular首先创建root view,并将宿主元素定位在data数组中下标为0的位置。之后,遍历所有组件并为每个view填充data。接下来,让我们深入了解变更检测机制。ChangeDetectorRef是抽象类,包含detectChanges和markForCheck等方法。在注入ChangeDetectorRef时,实际上获取的是从ChangeDetectorRef类拓展得到的ViewRef实例。为了更深入了解Ivy中的变更检测机制,本文将详细探讨内部方法,包括detectChanges、tick、scheduleTick、markViewDirty和markDirty等。detectChanges方法以同步方式在一个组件及其子组件上执行变更检测。尽管在某些情况下,直接调用detectChanges触发变更检测是合理的,但通常更推荐使用markDirty函数,等待未来的某个时间点通过调度器调用该函数。这是因为单个用户操作可能导致多个组件失效,同时,对每个组件进行变更检测效率较低。等待所有组件都被标记为dirty后,执行单次变更检测更为高效。用于在整个应用层面触发变更检测的tick方法类似于detectChanges方法,但仅在根组件上调用。此外,tick还会执行生命周期钩子,并基于组件的ChangeDetectionStrategy和dirty状态有条件地检查组件。scheduleTick用于调度整个应用的变更检测计划,它将多个调用合并在一个变更检测轮询中执行。当视图需要重新渲染时,通常通过调用markDirty方法间接调用scheduleTick方法。markViewDirty(markForCheck)将当前视图及其所有祖先视图标记为dirty。在Angular 5中,该方法向上遍历并确保对所有父级view进行检查。值得注意的是,在Ivy中,markForCheck并不会触发任何变更检测循环。markDirty将组件标记为dirty,这意味着调度器将在未来的某个时间点对该组件进行变更检测。对已标记为dirty的组件再次标记不会产生额外效果,每个组件树只会被调度一次变更检测。(使用不同的renderComponent构造的组件拥有不同的处理器)。 checkNoChanges方法通常不包含新的内容。在调试新的变更检测机制时,发现忘记安装zone.js。然而,应用能够正常运行,即使没有依赖zone.js,没有cdRef.detectChanges或tick。基于当前设计,对于采用OnPush的组件,Angular只有在特定情况下才会触发变更检测。这些规则同样适用于Ivy,如子组件存在一个output绑定,通过(input)事件触发,调用markForCheck方法。这解释了为什么在没有zone.js的情况下,应用仍然可以正常运行。关于ExpressionChangedAfterItHasBeenCheckedError问题,虽然操作类似,但顺序似乎有所变化。比如,Angular首先检测子组件,然后检测嵌入的视图。在demo中的ChildComponent展示了这种实现,应用动态方式观察这种变化,可以看到顺序与过去的视图引擎相似。在demo中还有一个可选的run angular complier按钮,可以检测其他场景。一次性字符串初始化在组件以字符串值方式接受颜色参数时,Angular将常量存储在负责创建和更新组件的代码之外,仅在创建模式中使用它。因此,Angular不再对这个绑定进行额外检查。在Ivy中,Angular编译器将常量存储在创建模式中,只有在创建组件时使用它,这使得容器不再创建文本节点。最后,通过构建一个小demo,我们展示了IDOM渲染的工作流程。IDOM关注构建和更新DOM树,其设计理念与Ivy有相似之处。通过测试方案,我们验证了更新文本节点的代码,使用浏览器工具可以观察到文本节点内容的变化。IDOM的核心理念是使用真实DOM与新树进行比较,以实现高效渲染。感谢阅读本文,希望您通过本文对Angular Ivy渲染引擎的变更检测机制有了更深入的理解。如需更多详细内容,可参考相关文档或深入研究Angular源代码。