通过单步调试的方式学习|通过单步调试的方式学习 Angular 中 TView 和 LView 的概念

问题描述 本文涉及到的代码位置:https://github.com/wangzixi-d...
看这样一组 parent Component 和 child Component:

@Component({ selector: 'child', template: `I am a child.` }) export class ChildViewComponent {}@Component({ selector: 'parent', template: `projected content: ` }) export class ParentComponent {}@Component({ selector: 'demo', template: ` ` }) export class Demo {}

其中 parent Component 定义了一个内容投影区域,通过下列高亮代码,将子 Component 的内容投射进来:
通过单步调试的方式学习|通过单步调试的方式学习 Angular 中 TView 和 LView 的概念
文章图片

即该区域:
通过单步调试的方式学习|通过单步调试的方式学习 Angular 中 TView 和 LView 的概念
文章图片

最后的运行时效果:
通过单步调试的方式学习|通过单步调试的方式学习 Angular 中 TView 和 LView 的概念
文章图片

问题分析 当上述应用被 load 但尚未完成 bootstrap 时,Ivy 将其解析为如下的 TView
const tChildComponentView = new TView( tData: [ new TElementNode(‘span’), new TTextNode(‘I am a child.’), ], …, ); const tParentComponentView = new TView( tData: [ new TElementNode(‘div’), new TTextNode(‘projected content: ‘), new TProjectionNode(), ], …, ); const tDemoAppView = new TView( tData: [ new TElementNode(‘parent’, [‘id’, ‘p1’]), new TElementNode(‘child’, [‘id’, ‘c1’]), new TElementNode(‘child’, [‘id’, ‘c2’]), ], …, )

接下来的步骤就是 bootstrap,具体的逻辑就是基于 TView 创建 LView
const lParentComponentView_p1 = new LView( tParentComponentView, new ParentComponent(…), document.createElement(‘div’), document.createText(‘projected content: ‘), ); const lChildComponentView_c1 = new LView( tChildComponentView, new ChildComponent(…), document.createElement(‘span’), document.createText(‘I am a child.’), ); const lChildComponentView_c2 = new LView( tChildComponentView, new ChildComponent(…), document.createElement(‘span’), document.createText(‘I am a child.’), ); const lDemoAppView = new LView( tDemoAppView, new DemoApp(…), document.createElement(‘parent’), lParentComponentView_p1, document.createElement(‘child’), lChildComponentView_c1, document.createElement(‘child’), lChildComponentView_c2, )

上述逻辑在调试器里如下图所示:
通过单步调试的方式学习|通过单步调试的方式学习 Angular 中 TView 和 LView 的概念
文章图片

其中 JerryAppComponent 被维护为 bootstrap Component:
通过单步调试的方式学习|通过单步调试的方式学习 Angular 中 TView 和 LView 的概念
文章图片

【通过单步调试的方式学习|通过单步调试的方式学习 Angular 中 TView 和 LView 的概念】上述代码展示了 TViewLView 二者的区别。
再看 ChildComponent,TView 的实例只有一个,而 LView 的实例却有两个,因为 ChildComponent 被使用了两次。 另一个关键区别是 LView 只存储特定于该组件实例的数据——例如组件实例和关联的 DOM 节点。 TView 存储在组件的所有实例之间共享的信息——例如需要创建哪些 DOM 节点
在上面的示例中,LView 显示为一个类(new LView(...)。实际上,我们将它存储为一个数组([...])。将 LView 存储为一个数组是出于内存性能的原因。 每个模板都有不同数量的 DOM 节点和子组件/指令,将其存储在数组中是最有效的方式。
使用数组进行存储的含义是不清楚在数组中的哪个位置存储实例数据。 TData 用于描述 LView 中每个位置存储的内容。 所以 LView 本身不足以推理,因为它在没有上下文的情况下存储值。 TView 描述了组件需要什么,但它不存储实例信息。 通过将 LView 和 TView 放在一起,Ivy 可以访问和推理 LView 中的值。 LView 存储值,而 TView 存储 LView 中值的含义,类似元数据或者 schema 的概念。
为简单起见,LView 仅存储 DOM 节点。 在实践中,LView 还存储绑定、注入器、净化器以及与视图状态相关的任何其他内容(在 TView/TData 中具有相应的条目。)
总结 考虑 View 和 View 的一种方法是将这些概念与面向对象的编程联系起来。 TView 就像类,而 View 就像类实例。

    推荐阅读