【鸿蒙应用实战开发】ArkUI构建之渲染控制和构建过程

13 篇文章 0 订阅
12 篇文章 0 订阅

ArkUI实现

编译期

1.通过声明式语法使用系统和自定义组件描述UI树
2.将装饰器修饰的 UI 组件树,转换成 ViewPU 树

运行时

1.监听并响应系统硬件的VSync信号
2.在测量和布局阶段,通过上面的ViewPU树进一步构建 FrameNode 树 和 RSNode 树
3.在布局和绘制阶段,通过 RSNode 录制绘制命令,然后使用IPC 发送命令到 RenderService 进程中,由RenderService完成 UI 绘制

转换前的代码

import { BasicDataSource } from './BasicDataSource';

class MyDataSource extends BasicDataSource {
  private dataArray: string[] = [];

  public totalCount(): number {
    return this.dataArray.length;
  }

  public getData(index: number): string {
    return this.dataArray[index];
  }

  public addData(index: number, data: string): void {
    this.dataArray.splice(index, 0, data);
    this.notifyDataAdd(index);
  }

  public pushData(data: string): void {
    this.dataArray.push(data);
    this.notifyDataAdd(this.dataArray.length - 1);
  }
}

@Entry
@Component
struct Index {
  @State message1: string = 'hello'
  message2: string = 'Hi'
  @State showMode: number = 0
  private data: MyDataSource = new MyDataSource();

  aboutToAppear() {
    for (let i = 0; i <= 20; i++) {
      this.data.pushData(`Hello ${i}`)
    }
  }

  build() {
    Column() {
      Row() {
        Column() {
          Text('the first text')
            .fontSize(50)
            .fontWeight(FontWeight.Bold)
          Text('the second text')
            .fontSize(50)
            .fontWeight(FontWeight.Bold)
        }
      }

      Row() {
        Column() {
          Text('the third text')
            .fontSize(50)
            .fontWeight(FontWeight.Bold)
        }
      }

      List({ space: 3 }) {
        LazyForEach(this.data, (item: string) => {
          ListItem() {
            Row() {
              Text(item).fontSize(50)
                .onAppear(() => {
                  console.info("appear:" + item)
                })
            }.margin({ left: 10, right: 10 })
          }
        }, (item: string) => item)
      }.cachedCount(5)

      ForEach([1, 2, 3], (item: number, index: number) => {
        Text(`item: ${item} index: ${index}`)
          .fontSize(50)
          .fontWeight(FontWeight.Bold
          )
      })

      if (this.showMode === 0) {
        Child({
          message1: this.message1,
          message2: this.message2
        })
      } else if (this.showMode === 1) {
        Child2()
      } else {
        Text("this is if else else branch")
      }

    }
  }
}

@Component
struct Child {
  @Link message1: string;
  @Prop message2: string;

  build() {
    Column() {
      Text(this.message1)
    }
  }
}

@Component
struct Child2 {
  private message: string = 'Hello';

  build() {
    Column() {
      Text(this.message)
    }
  }
}

转换成TS后的代码

if (!("finalizeConstruction" in ViewPU.prototype)) {
    Reflect.set(ViewPU.prototype, "finalizeConstruction", () => { });
}
interface Child2_Params {
    message?: string;
}
interface Child_Params {
    message1?: string;
    message2?: string;
}
interface Index_Params {
    message1?: string;
    message2?: string;
    showMode?: number;
    data?: MyDataSource;
}
import { BasicDataSource } from "@bundle:com.unravel.myapplication/entry/ets/pages/BasicDataSource";
class MyDataSource extends BasicDataSource {
    private dataArray: string[] = [];
    public totalCount(): number {
        return this.dataArray.length;
    }
    public getData(index: number): string {
        return this.dataArray[index];
    }
    public addData(index: number, data: string): void {
        this.dataArray.splice(index, 0, data);
        this.notifyDataAdd(index);
    }
    public pushData(data: string): void {
        this.dataArray.push(data);
        this.notifyDataAdd(this.dataArray.length - 1);
    }
}
class Index extends ViewPU {
    constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) {
        super(parent, __localStorage, elmtId, extraInfo);
        if (typeof paramsLambda === "function") {
            this.paramsGenerator_ = paramsLambda;
        }
        this.__message1 = new ObservedPropertySimplePU('hello', this, "message1");
        this.message2 = 'Hi';
        this.__showMode = new ObservedPropertySimplePU(0, this, "showMode");
        this.data = new MyDataSource();
        this.setInitiallyProvidedValue(params);
        this.finalizeConstruction();
    }
    setInitiallyProvidedValue(params: Index_Params) {
        if (params.message1 !== undefined) {
            this.message1 = params.message1;
        }
        if (params.message2 !== undefined) {
            this.message2 = params.message2;
        }
        if (params.showMode !== undefined) {
            this.showMode = params.showMode;
        }
        if (params.data !== undefined) {
            this.data = params.data;
        }
    }
    updateStateVars(params: Index_Params) {
    }
    purgeVariableDependenciesOnElmtId(rmElmtId) {
        this.__message1.purgeDependencyOnElmtId(rmElmtId);
        this.__showMode.purgeDependencyOnElmtId(rmElmtId);
    }
    aboutToBeDeleted() {
        this.__message1.aboutToBeDeleted();
        this.__showMode.aboutToBeDeleted();
        SubscriberManager.Get().delete(this.id__());
        this.aboutToBeDeletedInternal();
    }
    private __message1: ObservedPropertySimplePU<string>;
    get message1() {
        return this.__message1.get();
    }
    set message1(newValue: string) {
        this.__message1.set(newValue);
    }
    private message2: string;
    private __showMode: ObservedPropertySimplePU<number>;
    get showMode() {
        return this.__showMode.get();
    }
    set showMode(newValue: number) {
        this.__showMode.set(newValue);
    }
    private data: MyDataSource;
    aboutToAppear() {
        for (let i = 0; i <= 20; i++) {
            this.data.pushData(`Hello ${i}`);
        }
    }
    initialRender() {
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Column.create();
        }, Column);
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Row.create();
        }, Row);
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Column.create();
        }, Column);
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Text.create('the first text');
            Text.fontSize(50);
            Text.fontWeight(FontWeight.Bold);
        }, Text);
        Text.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Text.create('the second text');
            Text.fontSize(50);
            Text.fontWeight(FontWeight.Bold);
        }, Text);
        Text.pop();
        Column.pop();
        Row.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Row.create();
        }, Row);
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Column.create();
        }, Column);
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Text.create('the third text');
            Text.fontSize(50);
            Text.fontWeight(FontWeight.Bold);
        }, Text);
        Text.pop();
        Column.pop();
        Row.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            List.create({ space: 3 });
            List.cachedCount(5);
        }, List);
        {
            const __lazyForEachItemGenFunction = _item => {
                const item = _item;
                {
                    const itemCreation2 = (elmtId, isInitialRender) => {
                        ListItem.create(() => { }, false);
                    };
                    const observedDeepRender = () => {
                        this.observeComponentCreation2(itemCreation2, ListItem);
                        this.observeComponentCreation2((elmtId, isInitialRender) => {
                            Row.create();
                            Row.margin({ left: 10, right: 10 });
                        }, Row);
                        this.observeComponentCreation2((elmtId, isInitialRender) => {
                            Text.create(item);
                            Text.fontSize(50);
                            Text.onAppear(() => {
                                console.info("appear:" + item);
                            });
                        }, Text);
                        Text.pop();
                        Row.pop();
                        ListItem.pop();
                    };
                    observedDeepRender();
                }
            };
            const __lazyForEachItemIdFunc = (item: string) => item;
            LazyForEach.create("1", this, this.data, __lazyForEachItemGenFunction, __lazyForEachItemIdFunc);
            LazyForEach.pop();
        }
        List.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            ForEach.create();
            const forEachItemGenFunction = (_item, index: number) => {
                const item = _item;
                this.observeComponentCreation2((elmtId, isInitialRender) => {
                    Text.create(`item: ${item} index: ${index}`);
                    Text.fontSize(50);
                    Text.fontWeight(FontWeight.Bold);
                }, Text);
                Text.pop();
            };
            this.forEachUpdateFunction(elmtId, [1, 2, 3], forEachItemGenFunction, undefined, true, false);
        }, ForEach);
        ForEach.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            If.create();
            if (this.showMode === 0) {
                this.ifElseBranchUpdateFunction(0, () => {
                    {
                        this.observeComponentCreation2((elmtId, isInitialRender) => {
                            if (isInitialRender) {
                                let componentCall = new Child(this, {
                                    message1: this.__message1,
                                    message2: this.message2
                                }, undefined, elmtId, () => { }, { page: "entry/src/main/ets/pages/Index.ets", line: 81 });
                                ViewPU.create(componentCall);
                                let paramsLambda = () => {
                                    return {
                                        message1: this.message1,
                                        message2: this.message2
                                    };
                                };
                                componentCall.paramsGenerator_ = paramsLambda;
                            }
                            else {
                                this.updateStateVarsOfChildByElmtId(elmtId, {
                                    message2: this.message2
                                });
                            }
                        }, { name: "Child" });
                    }
                });
            }
            else if (this.showMode === 1) {
                this.ifElseBranchUpdateFunction(1, () => {
                    {
                        this.observeComponentCreation2((elmtId, isInitialRender) => {
                            if (isInitialRender) {
                                let componentCall = new Child2(this, {}, undefined, elmtId, () => { }, { page: "entry/src/main/ets/pages/Index.ets", line: 86 });
                                ViewPU.create(componentCall);
                                let paramsLambda = () => {
                                    return {};
                                };
                                componentCall.paramsGenerator_ = paramsLambda;
                            }
                            else {
                                this.updateStateVarsOfChildByElmtId(elmtId, {});
                            }
                        }, { name: "Child2" });
                    }
                });
            }
            else {
                this.ifElseBranchUpdateFunction(2, () => {
                    this.observeComponentCreation2((elmtId, isInitialRender) => {
                        Text.create("this is if else else branch");
                    }, Text);
                    Text.pop();
                });
            }
        }, If);
        If.pop();
        Column.pop();
    }
    rerender() {
        this.updateDirtyElements();
    }
    static getEntryName(): string {
        return "Index";
    }
}
class Child extends ViewPU {
    constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) {
        super(parent, __localStorage, elmtId, extraInfo);
        if (typeof paramsLambda === "function") {
            this.paramsGenerator_ = paramsLambda;
        }
        this.__message1 = new SynchedPropertySimpleTwoWayPU(params.message1, this, "message1");
        this.__message2 = new SynchedPropertySimpleOneWayPU(params.message2, this, "message2");
        this.setInitiallyProvidedValue(params);
        this.finalizeConstruction();
    }
    setInitiallyProvidedValue(params: Child_Params) {
    }
    updateStateVars(params: Child_Params) {
        this.__message2.reset(params.message2);
    }
    purgeVariableDependenciesOnElmtId(rmElmtId) {
        this.__message1.purgeDependencyOnElmtId(rmElmtId);
        this.__message2.purgeDependencyOnElmtId(rmElmtId);
    }
    aboutToBeDeleted() {
        this.__message1.aboutToBeDeleted();
        this.__message2.aboutToBeDeleted();
        SubscriberManager.Get().delete(this.id__());
        this.aboutToBeDeletedInternal();
    }
    private __message1: SynchedPropertySimpleTwoWayPU<string>;
    get message1() {
        return this.__message1.get();
    }
    set message1(newValue: string) {
        this.__message1.set(newValue);
    }
    private __message2: SynchedPropertySimpleOneWayPU<string>;
    get message2() {
        return this.__message2.get();
    }
    set message2(newValue: string) {
        this.__message2.set(newValue);
    }
    initialRender() {
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Column.create();
        }, Column);
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Text.create(this.message1);
        }, Text);
        Text.pop();
        Column.pop();
    }
    rerender() {
        this.updateDirtyElements();
    }
}
class Child2 extends ViewPU {
    constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) {
        super(parent, __localStorage, elmtId, extraInfo);
        if (typeof paramsLambda === "function") {
            this.paramsGenerator_ = paramsLambda;
        }
        this.message = 'Hello';
        this.setInitiallyProvidedValue(params);
        this.finalizeConstruction();
    }
    setInitiallyProvidedValue(params: Child2_Params) {
        if (params.message !== undefined) {
            this.message = params.message;
        }
    }
    updateStateVars(params: Child2_Params) {
    }
    purgeVariableDependenciesOnElmtId(rmElmtId) {
    }
    aboutToBeDeleted() {
        SubscriberManager.Get().delete(this.id__());
        this.aboutToBeDeletedInternal();
    }
    private message: string;
    initialRender() {
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Column.create();
        }, Column);
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Text.create(this.message);
        }, Text);
        Text.pop();
        Column.pop();
    }
    rerender() {
        this.updateDirtyElements();
    }
}
registerNamedRoute(() => new Index(undefined, {}), "", { bundleName: "com.unravel.myapplication", moduleName: "entry", pagePath: "pages/Index" });

build 转换前后

1.转换前后的代码如图,我们看到最终是在 initialRender 中完成具体的组件的搭建

2.创建每个系统组件和自定义组件的时候都是通过 observeComponentCreation2 来完成的

3.整个过程以栈的形式运作,每个组件create入栈,pop出栈,最终组成组件树
在这里插入图片描述

一帧的核心绘制流程

在这里插入图片描述

1.Component树经过测算后转换成FrameNode树,再经过布局、绘制操作转换成RSNode

2.RSNode 录制指令,交给RSCanvasNode转换成渲染指令,然后通过IPC发送给RenderService再经由GPU、CPU绘制出来

if/else 转换前后

在这里插入图片描述

一、If 是一个单独的组件,也可以通过Create、Pop创建和销毁
在这里插入图片描述

二、有多少个分支,就会创建多少个 ifElseBranchUpdateFunction,它的第一个参数是唯一的一个数字,从0递增,第二个参数是一个箭头函数,用于创建组件
在这里插入图片描述

ForEach转换前后

可以对比ForEach 的键值生成规则、组件创建规则 理解代码

developer.huawei.com/consumer/cn…

在这里插入图片描述

一、ForEach 是一个单独的组件,也可以通过Create、Pop创建和销毁
在这里插入图片描述

二、ForEach的更新是通过 forEachUpdateFunction 来完成的,包括id生成,diff更新等

/**
   Partial updates for ForEach.
   * @param elmtId ID of element.
   * @param itemArray Array of items for use of itemGenFunc.
   * @param itemGenFunc Item generation function to generate new elements. If index parameter is
   *                    given set itemGenFuncUsesIndex to true.
   * @param idGenFunc   ID generation function to generate unique ID for each element. If index parameter is
   *                    given set idGenFuncUsesIndex to true.
   * @param itemGenFuncUsesIndex itemGenFunc optional index parameter is given or not.
   * @param idGenFuncUsesIndex idGenFunc optional index parameter is given or not.
   */
  public forEachUpdateFunction(
    elmtId: number,
    itemArray: Array<any>,
    itemGenFunc: (item: any, index?: number) => void,
    idGenFunc?: (item: any, index?: number) => string,
    itemGenFuncUsesIndex: boolean = false,
    idGenFuncUsesIndex: boolean = false
  ): void {
    if (itemArray === null || itemArray === undefined) {
      return;
    }

    if (itemGenFunc === null || itemGenFunc === undefined) {
      return;
    }
    // 没有传入生成id的函数,默认使用带index的生成函数
    if (idGenFunc === undefined) {
      idGenFuncUsesIndex = true;
      // catch possible error caused by Stringify and re-throw an Error with a meaningful (!) error message
      idGenFunc = (item: any, index: number): string => {
        try {
      // 默认id函数:通过index拼接item的json串
          return `${index}__${JSON.stringify(item)}`;
        } catch (e) {
          throw new Error(
            ` ForEach id ${elmtId}: use of default id generator function not possible on provided data structure. Need to specify id generator function (ForEach 3rd parameter). Application Error!`
          );
        }
      };
    }

    let diffIndexArray = []; // New indexes compared to old one.
    let newIdArray = [];
    let idDuplicates = [];
    const arr = itemArray; // just to trigger a 'get' onto the array

    // ID gen is with index.
    if (idGenFuncUsesIndex) {
      // Create array of new ids.
      arr.forEach((item, indx) => {
        newIdArray.push(idGenFunc(item, indx));
      });
    } else {
    // 如果传入的生成id的函数不带index,但是生成item的函数带index.也会拼接一个index
      // Create array of new ids.
      arr.forEach((item, index) => {
        newIdArray.push(
          `${itemGenFuncUsesIndex ? index + "_" : ""}` + idGenFunc(item)
        );
      });
    }

    // Set new array on C++ side.
    // C++ returns array of indexes of newly added array items.
    // these are indexes in new child list.
    ForEach.setIdArray(elmtId, newIdArray, diffIndexArray, idDuplicates);
    // Item gen is with index.
    diffIndexArray.forEach((indx) => {
      ForEach.createNewChildStart(newIdArray[indx], this);
      if (itemGenFuncUsesIndex) {
        itemGenFunc(arr[indx], indx);
      } else {
        itemGenFunc(arr[indx]);
      }
      ForEach.createNewChildFinish(newIdArray[indx], this);
    });
  }

LazyForEach 转换前后

在这里插入图片描述

一、LazyForEach 是一个单独的组件,也可以通过Create、Pop创建和销毁
create参数中的builder和idfunc都是我们生成的函数
在这里插入图片描述

import 转换前后

在这里插入图片描述

无论是本地路径引入还是通过har包引入,import转换后都转换成了完全形式的引入
一些引入但是没有用到的变量,编译后会被自动tree shaking

自定义组件 转化前后

1.自定义组件最终都会转换为 ViewPU的子类

2.自定义组件的参数 会被集合到一个interface定义中,命名参数传递也是基于此实现

3.普通变量不做改变,状态变量会被重写为getter和setter 同时生成双下划线开头的状态类
在这里插入图片描述

在组件构建的时候就会通过传入的参数初始化对应的私有状态变量
在这里插入图片描述

系统组件

void RegisterAllModule(BindingTarget globalObj, void* nativeEngine)
系统组件和自定义组件不同,每一个系统组件都绑定了一个对应的C++类
所有的组件都通过 RegisterAllModule 进行了注册。
在这里插入图片描述

static const std::unordered_map<std::string, std::function<void(BindingTarget)>> bindFuncs =
系统组件和TS类的映射关系如下
在这里插入图片描述

以Text为例

首先在Bind方法内声明了类名为Text,然后将一些属性绑定到了C++底层的方法
在这里插入图片描述

最后继承并绑定globalObj的属性,也就是所有组件的公共属性
在这里插入图片描述

JSClass::Declare

C++底层是通过模板类来创建的组件类。生成的类有静态方法、对象方法、getter/setter以及类方法等
在这里插入图片描述

void JsiClass::StaticMethod

在这里插入图片描述

JSClass::InheritAndBind(globalObj)

在这里插入图片描述

initialRender:构建UI树

observeComponentCreation2

每个组件的创建都是通过 observeComponentCreation2 完成的。
在这里插入图片描述

原有的闭包被封装进updateFunc,另外还使用了两个Map存储组件id到更新函数以及组件id到组件实例的映射。这两个Map用于状态变化时找到组件并更新组件
在这里插入图片描述

create

TextModel::Create

看一下Text的create方法,最终实现调用了 TextModel::GetInstance()->Create(data);
在这里插入图片描述

TextModelNG::Create

TextModel的实际实现根据条件可能是TextModelNG或TextModel,我们进入TextModelNG,里面逻辑会根据节点id判断是否已经有对应组件,没有才进行创建。之后将这个节点进行了入栈
在这里插入图片描述

很简单,就是一个入栈操作
在这里插入图片描述

pop

JSContainerBase Pop方法

Pop方法位于JSText的父类 JSContainerBase 中
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ViewStackModel::PopContainer

Pop方法是对 ViewStackModel::GetInstance()->PopContainer(); 的包装

在节点是AtomicNode的时候一直出栈,直到栈中只保留一个节点
在这里插入图片描述

isAtomicNode也有解释,是指button、image、自定义组件等等,只有Create函数没有Pop函数
在这里插入图片描述

ViewStackProcessor::Pop

在这里插入图片描述

ViewStackProcessor::Finish

在这里插入图片描述

小结

1.任何组件的创建函数 都被包裹在 observeComponentCreation2 函数中,这个函数内部会将组件创建函数包装成一个updateFunc函数并存储起来,方便状态变量变化时取到组件实例,进而更新UI
2.create 方法会将 UI 节点入栈;
3.pop 方法会将 UI 节点出栈,且将该节点挂载到栈顶节点下;
4.通过 create 和 pop 方法,以及编译期间的层级关系,即可构造出一颗 UI 树

ViewPU简析

    /*
 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *  * ViewPU - View for Partial Update
 *
* all definitions in this file are framework internal
*/

type DFXCommand = { what: string, viewId: number, isRecursive: boolean };
type RecycleUpdateFunc = (elmtId: number, isFirstRender: boolean, recycleNode: ViewPU) => void;

abstract class ViewPU extends PUV2ViewBase
  implements IViewPropertiesChangeSubscriber, IView {

  // flag for initial rendering or re-render on-going.
  // 正在渲染的标记位
  private isRenderInProgress: boolean = false;

  // flag for initial rendering being done
  // 首次渲染完成的标记位
  private isInitialRenderDone: boolean = false;

  private runReuse_: boolean = false;

  private paramsGenerator_: () => Object;

  /**
  * 按照Map保存Watch的回调函数,key是回调函数名,value是回调函数
  * 比如
  * @State @Watch('onShowModeChange') showMode: number = 0
  *  onShowModeChange() {
    * console.info("showMode changed")
  *  }
    * 则watchedProps = {'onShowModeChange' : onShowModeChange}
  **/
  private watchedProps: Map<string, (propName: string) => void>
    = new Map<string, (propName: string) => void>();

  private recycleManager_: RecycleManager = undefined;

  // @Provide'd variables by this class and its ancestors
  /**
    * 本类以及祖先提供的Provide变量,和watchedProps类似使用Map存储
  * @Provide('hhhh') a: boolean = false
    * providedVars_ = {'hhh': ObservedPropertyAbstractPU<boolean>}
  **/
  protected providedVars_: Map<string, ObservedPropertyAbstractPU<any>> = new Map<string, ObservedPropertyAbstractPU<any>>();

  // Set of dependent elmtIds that need partial update
  // during next re-render
  // 在下次重新渲染时需要部分更新的依赖elmtid集合
  protected dirtDescendantElementIds_: Set<number> = new Set<number>();

  // my LocalStorage instance, shared with ancestor Views.
  // create a default instance on demand if none is initialized
  // LocalStorage实例,与祖先视图共享。如果没有初始化,则根据需要创建一个默认实例
  // localStorage_ 的 getter中使用
  protected localStoragebackStore_: LocalStorage = undefined;

  // 存储可观测的状态变量,ownObservedPropertiesStore_的getter中使用
  private ownObservedPropertiesStore__?: Set<ObservedPropertyAbstractPU<any>>;

  private get ownObservedPropertiesStore_() {
    if (!this.ownObservedPropertiesStore__) {
      // lazy init
      this.ownObservedPropertiesStore__ = new Set<ObservedPropertyAbstractPU<any>>();
      this.obtainOwnObservedProperties();
    }
    return this.ownObservedPropertiesStore__;
  }

  // 获取本组件拥有的可观测属性
  protected obtainOwnObservedProperties(): void {
    let usesStateMgmtVersion = 0;
    Object.getOwnPropertyNames(this)
      .filter((propName) => {
    // 以__开头,同时不以__ob_、___comp_、___watch_开头的属性
        // do not include backing store, and ObserveV2/MonitorV2/ComputedV2 meta data objects
        return (propName.startsWith('__') &&
          !propName.startsWith(ObserveV2.OB_PREFIX) &&
          !propName.startsWith(MonitorV2.WATCH_PREFIX) &&
          !propName.startsWith(ComputedV2.COMPUTED_PREFIX));
      })
      .forEach((propName) => {
        const stateVar = Reflect.get(this, propName) as Object;
    // 存储 类型是object并且有notifyPropertyHasChangedPU属性的状态变量
        if (stateVar && typeof stateVar === 'object' && 'notifyPropertyHasChangedPU' in stateVar) {
          stateMgmtConsole.debug(`... add state variable ${propName} to ${stateVar}`);
          this.ownObservedPropertiesStore_.add(stateVar as unknown as ObservedPropertyAbstractPU<any>);
          usesStateMgmtVersion = 2;
        } else {
          stateMgmtConsole.debug(`${this.debugInfo__()} ${propName} application may use an unregular naming style, or stateVar may be Non-Object.`);
        }
      });

    if (this.isViewV3 == true) {
      if (usesStateMgmtVersion == 2) {
    // 不能在V3版本的View中使用V2版本的状态管理
        const error = `${this.debugInfo__()}: mixed use of stateMgmt V2 and V3 variable decorators. Application error!`;
        stateMgmtConsole.applicationError(error);
        throw new Error(error);
      }
    }
    stateMgmtConsole.debug(`${this.debugInfo__()}: uses stateMgmt version ${this.isViewV3 == true ? 3 : 2}`);
  }

  public get localStorage_(): LocalStorage {
  // 如果父类有localStorage_就是用父类的
    if (!this.localStoragebackStore_ && this.getParent()) {
      stateMgmtConsole.debug(`${this.debugInfo__()}: constructor: get localStorage_ : Using LocalStorage instance of the parent View.`);
      this.localStoragebackStore_ = this.getParent().localStorage_;
    }
  // 如果父类没有localStorage_,创建一个空的Storage
    if (!this.localStoragebackStore_) {
      stateMgmtConsole.info(`${this.debugInfo__()}: constructor: is accessing LocalStorage without being provided an instance. Creating a default instance.`);
      this.localStoragebackStore_ = new LocalStorage({ /* empty */ });
    }
    return this.localStoragebackStore_;
  }
  
  // localStorage_ 的 setter方法,做一些重复赋值判断逻辑
  public set localStorage_(instance: LocalStorage) {
    if (!instance) {
      // setting to undefined not allowed
      return;
    }
    if (this.localStoragebackStore_) {
      stateMgmtConsole.applicationError(`${this.debugInfo__()}: constructor: is setting LocalStorage instance twice. Application error.`);
    }
    this.localStoragebackStore_ = instance;
  }

  // FIXME
  // 指示这是 V2 还是 V3 组件 
  // indicate if this is  V2 or a V3 component
  // 默认为 V2,在使用 instanceOf 拆分 ViewPU 和 ViewV3 时,遇到第一个 V3 装饰器变量时变为 V3
  // V2 by default, changed to V3 by the first V3 decorated variable
  // when splitting ViewPU and ViewV3
  // 在此之前,这是一个解决方案
  // use instanceOf. Until then, this is a workaround.
  // @state, @track 等 V3 装饰器函数会修改 isViewV3 为 true (装饰器可以修改原型中的函数)
  // @state, @track, etc V3 decorator functions modify isViewV3 to return true
  // (decorator can modify functions in prototype)
  // FIXME
  private get isViewV3(): boolean {
    return false;
  }

  /**
   * Create a View
   *
   * 1. option: top level View, specify
   *    - compilerAssignedUniqueChildId must specify
   *    - parent=undefined
   *    - localStorage  must provide if @LocalSTorageLink/Prop variables are used
   *      in this View or descendant Views.
   *
   * 2. option: not a top level View
   *    - compilerAssignedUniqueChildId must specify
   *    - parent must specify
   *    - localStorage do not specify, will inherit from parent View.
   *
  */
/**

创建一个 View
选项:顶级 View,需要指定
必须指定 compilerAssignedUniqueChildId
parent=undefined
如果在此 View 或子 View 中使用了 @LocalSTorageLink/Prop 变量,则必须提供 localStorage
选项:非顶级 View
必须指定 compilerAssignedUniqueChildId
必须指定 parent
不需要指定 localStorage,将从父 View 继承。
*/
  constructor(parent: IView, localStorage: LocalStorage, elmtId: number = UINodeRegisterProxy.notRecordingDependencies, extraInfo: ExtraInfo = undefined) {
    super(parent, elmtId, extraInfo);
    // if set use the elmtId also as the ViewPU object's subscribable id.
    // these matching is requirement for updateChildViewById(elmtId) being able to
    // find the child ViewPU object by given elmtId
    // 如果设置了将 elmtId 用作 ViewPU 对象的可订阅 id。 updateChildViewById(elmtId) 通过给定的 elmtId 找到子 ViewPU 对象需满足下面的匹配关系
    //this.id_ = elmtId == UINodeRegisterProxy.notRecordingDependencies ? SubscriberManager.MakeId() : elmtId;

    this.localStoragebackStore_ = undefined;
    stateMgmtConsole.debug(`ViewPU constructor: Creating @Component '${this.constructor.name}' from parent '${parent?.constructor.name}'`);

    // 传递了localStorage则使用传递的localStorage
    if (localStorage) {
      this.localStorage_ = localStorage;
      stateMgmtConsole.debug(`${this.debugInfo__()}: constructor: Using LocalStorage instance provided via @Entry or view instance creation.`);
    }
  // 将此组件添加到 SubscriberManager
    SubscriberManager.Add(this);
    stateMgmtConsole.debug(`${this.debugInfo__()}: constructor: done`);
  }


  // inform the subscribed property
  // that the View and thereby all properties
  // are about to be deleted
  // 通知已订阅的属性, 即将删除View 以及所有相关的属性
  abstract aboutToBeDeleted(): void;
  
  aboutToReuse(params: Object): void { }

  aboutToRecycle(): void { }

  // super class will call this function from
  // its aboutToBeDeleted implementation
  // 父类的aboutToBeDeleted 实现中会调用此函数
  protected aboutToBeDeletedInternal(): void {
    stateMgmtConsole.debug(`${this.debugInfo__()}: aboutToBeDeletedInternal`);
    // if this isDeleting_ is true already, it may be set delete status recursively by its parent, so it is not necessary
    // to set and recursively set its children any more
    // 如果this isDeleting_已经为真,它可以被父节点递归地设置为删除状态,所以没有必要再递归地设置它的子节点
    if (!this.isDeleting_) {
      this.isDeleting_ = true;
      this.setDeleteStatusRecursively();
    }
    // tell UINodeRegisterProxy that all elmtIds under
    // this ViewPU should be treated as already unregistered
    // 告诉UINodeRegisterProxy, 这个ViewPU下的所有elmtid应该被视为已经未注册
    stateMgmtConsole.debug(`${this.constructor.name}: aboutToBeDeletedInternal `);

    // purge the elmtIds owned by this viewPU from the updateFuncByElmtId and also the state variable dependent elmtIds
    // 从updateFuncByElmtId和依赖于状态变量的elmtid中清除这个viewPU拥有的elmtid。即我们之前提到的两个Map
    Array.from(this.updateFuncByElmtId.keys()).forEach((elmtId: number) => {
      this.purgeDeleteElmtId(elmtId);
    })

    if (this.hasRecycleManager()) {
      this.getRecycleManager().purgeAllCachedRecycleNode();
    }

    // un-registration of ElementIDs
    stateMgmtConsole.debug(`${this.debugInfo__()}: onUnRegElementID`);

    // it will unregister removed elmtIds from all ViewPu, equals purgeDeletedElmtIdsRecursively
    // 它将注销从所有ViewPu中删除的elmtIds,等于purgedeletedelmtids递归
    this.purgeDeletedElmtIds();

  // 一旦它的子元素被取消注册 就 取消注册它自己的id
    // un-registers its own id once its children are unregistered above
    //FIXME: Uncomment once photos app avoids rerendering of removed elementIds
    //UINodeRegisterProxy unregisterRemovedElmtsFromViewPUs([this id__()]);

    stateMgmtConsole.debug(`${this.debugInfo__()}: onUnRegElementID  - DONE`);

    // in case this ViewPU is currently frozen
    // 如果这个ViewPU当前处于冻结状态。就从inactiveComponents_移除
    PUV2ViewBase.inactiveComponents_.delete(`${this.constructor.name}[${this.id__()}]`);

    // FIXME needed ?
    MonitorV2.clearWatchesFromTarget(this);

  // 清空 更新函数map,watched变量,provided的状态变量,本组件使用的状态变量
    this.updateFuncByElmtId.clear();
    this.watchedProps.clear();
    this.providedVars_.clear();
    if (this.ownObservedPropertiesStore__) {
      this.ownObservedPropertiesStore__.clear();
    }
    // 从父组件中移除自身
    if (this.getParent()) {
      this.getParent().removeChild(this);
    }
    // localStorage置空
    this.localStoragebackStore_ = undefined;
  }

  protected debugInfoStateVars(): string {
    let result: string = `|--${this.constructor.name}[${this.id__()}]`;
    Object.getOwnPropertyNames(this)
      .filter((varName: string) => varName.startsWith('__') && !varName.startsWith(ObserveV2.OB_PREFIX))
      .forEach((varName) => {
        const prop: any = Reflect.get(this, varName);
        if ('debugInfoDecorator' in prop) {
          const observedProp = prop as ObservedPropertyAbstractPU<any>;
          result += `\n  ${observedProp.debugInfoDecorator()} '${observedProp.info()}'[${observedProp.id__()}]`;
          result += `\n  ${observedProp.debugInfoSubscribers()}`;
          result += `\n  ${observedProp.debugInfoSyncPeers()}`;
          result += `\n  ${observedProp.debugInfoDependentElmtIds()}`;
          result += `\n  ${observedProp.debugInfoDependentComponents()}`;
        }
      });
    return result;
  }

  /**
  * 当相应的CustomNode的活动状态发生变化时,ArkUI引擎将调用该函数
 * ArkUI engine will call this function when the corresponding CustomNode's active status change.
  * @param active为active,为false为inactive
 * @param active true for active, false for inactive
 */
  public setActiveInternal(active: boolean): void {
    stateMgmtProfiler.begin('ViewPU.setActive');
    // 如果没有指定 freezeWhenInactive 不做处理
    if (!this.isCompFreezeAllowed()) {
      stateMgmtConsole.debug(`${this.debugInfo__()}: ViewPU.setActive. Component freeze state is ${this.isCompFreezeAllowed()} - ignoring`);
      stateMgmtProfiler.end();
      return;
    }
    stateMgmtConsole.debug(`${this.debugInfo__()}: ViewPU.setActive ${active ? ' inActive -> active' : 'active -> inActive'}`);
    this.isActive_ = active;
    if (this.isActive_) {
      this.onActiveInternal();
    } else {
      this.onInactiveInternal();
    }
    stateMgmtProfiler.end();
  }
  // 变为活跃
  private onActiveInternal(): void {
    if (!this.isActive_) {
      return;
    }

    stateMgmtConsole.debug(`${this.debugInfo__()}: onActiveInternal`);
  // 执行延迟的初始化
    this.performDelayedUpdate();
    // 把不活跃的组件移除
    // Remove the active component from the Map for Dfx
    ViewPU.inactiveComponents_.delete(`${this.constructor.name}[${this.id__()}]`);
  // 遍历子组件,将子组件置为active
    for (const child of this.childrenWeakrefMap_.values()) {
      const childViewPU: IView | undefined = child.deref();
      if (childViewPU) {
        childViewPU.setActiveInternal(this.isActive_);
      }
    }
  }

  // 变为不活跃
  private onInactiveInternal(): void {
    if (this.isActive_) {
      return;
    }

    stateMgmtConsole.debug(`${this.debugInfo__()}: onInactiveInternal`);
    // 设置本组件依赖的状态变量 开启延迟通知
    for (const stateLinkProp of this.ownObservedPropertiesStore_) {
      stateLinkProp.enableDelayedNotification();
    }
    // 将本组件不活跃标志添加进去
    // Add the inactive Components to Map for Dfx listing
    ViewPU.inactiveComponents_.add(`${this.constructor.name}[${this.id__()}]`);
  // 将子组件设置为不活跃
    for (const child of this.childrenWeakrefMap_.values()) {
      const childViewPU: IView | undefined = child.deref();
      if (childViewPU) {
        childViewPU.setActiveInternal(this.isActive_);
      }
    }
  }


  // abstract functions to be implemented by application defined class / transpiled code
  // 清空某个组件依赖的状态变量
  protected abstract purgeVariableDependenciesOnElmtId(removedElmtId: number);
  // 初次渲染
  protected abstract initialRender(): void;
  // 重新渲染
  protected abstract rerender(): void;

  // 更新回收利用
  public abstract updateRecycleElmtId(oldElmtId: number, newElmtId: number): void;
  // 更新状态变量
  public abstract updateStateVars(params: Object);

  // 初始化渲染View,里面初始化一些变量和标志位
  public initialRenderView(): void {
    stateMgmtProfiler.begin('ViewPU.initialRenderView');
    this.obtainOwnObservedProperties();
    this.isRenderInProgress = true;
    this.initialRender();
    this.isRenderInProgress = false;
    this.isInitialRenderDone = true;
    stateMgmtProfiler.end();
  }

  // 更新某个组件
  public UpdateElement(elmtId: number): void {
    stateMgmtProfiler.begin('ViewPU.UpdateElement');
    if (elmtId == this.id__()) {
      // do not attempt to update itself.
      // a @Prop can add a dependency of the ViewPU onto itself. Ignore it.
      stateMgmtProfiler.end();
      return;
    }

    // do not process an Element that has been marked to be deleted
    const entry: UpdateFuncRecord | undefined = this.updateFuncByElmtId.get(elmtId);
    const updateFunc = entry ? entry.getUpdateFunc() : undefined;

    if (typeof updateFunc !== 'function') {
      stateMgmtConsole.debug(`${this.debugInfo__()}: UpdateElement: update function of elmtId ${elmtId} not found, internal error!`);
    } else {
      stateMgmtConsole.debug(`${this.debugInfo__()}: UpdateElement: re-render of ${entry.getComponentName()} elmtId ${elmtId} start ...`);
      this.isRenderInProgress = true;
      stateMgmtProfiler.begin('ViewPU.updateFunc');
      // 执行更新函数
      updateFunc(elmtId, /* isFirstRender */ false);
      stateMgmtProfiler.end();
      stateMgmtProfiler.begin('ViewPU.finishUpdateFunc (native)');
    // 执行完成更新函数
      this.finishUpdateFunc(elmtId);
      stateMgmtProfiler.end();
      this.isRenderInProgress = false;
      stateMgmtConsole.debug(`${this.debugInfo__()}: UpdateElement: re-render of ${entry.getComponentName()} elmtId ${elmtId} - DONE`);
    }
    stateMgmtProfiler.end();
  }

  /**
  通过执行所有更新函数来强制完成渲染/更新
   * force a complete rerender / update by executing all update functions
  首先执行常规渲染
   * exec a regular rerender first
   *
   * @param deep recurse all children as well
   *
   * framework internal functions, apps must not call
   */
  public forceCompleteRerender(deep: boolean = false): void {
    stateMgmtProfiler.begin('ViewPU.forceCompleteRerender');
    stateMgmtConsole.warn(`${this.debugInfo__()}: forceCompleteRerender - start.`);

    // see which elmtIds are managed by this View
    // and clean up all book keeping for them
    // 查看哪些elmtid由这个视图管理,并清除它们的所有记录
    this.purgeDeletedElmtIds();

    Array.from(this.updateFuncByElmtId.keys()).sort(ViewPU.compareNumber).forEach(elmtId => this.UpdateElement(elmtId));

    if (deep) {
      this.childrenWeakrefMap_.forEach((weakRefChild: WeakRef<ViewPU>) => {
        const child = weakRefChild.deref();
        if (child) {
          if (child instanceof ViewPU) {
            child.forceCompleteRerender(true);
          } else {
            throw new Error('forceCompleteRerender not implemented for ViewV2, yet');
          }
        }
      });
    }
    stateMgmtConsole.debug(`${this.debugInfo__()}: forceCompleteRerender - end`);
    stateMgmtProfiler.end();
  }

  /**
通过执行update函数在特定节点上强制完成渲染/更新
   * force a complete rerender / update on specific node by executing update function.
   *
   * @param elmtId which node needs to update.
   *
   * framework internal functions, apps must not call
   */
  public forceRerenderNode(elmtId: number): void {
    stateMgmtProfiler.begin('ViewPU.forceRerenderNode');
    // see which elmtIds are managed by this View
    // and clean up all book keeping for them
    // 查看哪些elmtid由这个视图管理,并清除它们的所有记录
    this.purgeDeletedElmtIds();
    this.UpdateElement(elmtId);

    // remove elemtId from dirtDescendantElementIds.
    this.dirtDescendantElementIds_.delete(elmtId);
    stateMgmtProfiler.end();
  }

  // implements IMultiPropertiesChangeSubscriber
  // View属性变化时的回调
  viewPropertyHasChanged(varName: PropertyInfo, dependentElmtIds: Set<number>): void {
    stateMgmtProfiler.begin('ViewPU.viewPropertyHasChanged');
    aceTrace.begin('ViewPU.viewPropertyHasChanged', this.constructor.name, varName, dependentElmtIds.size);
    if (this.isRenderInProgress) {
      stateMgmtConsole.applicationError(`${this.debugInfo__()}: State variable '${varName}' has changed during render! It's illegal to change @Component state while build (initial render or re-render) is on-going. Application error!`);
    }

    this.syncInstanceId();
  // 如果有依赖的视图id,并且非首次渲染。
    if (dependentElmtIds.size && !this.isFirstRender()) {
      if (!this.dirtDescendantElementIds_.size && !this.runReuse_) {
     // 在添加第一个elmtid时将ComposedElement标记为dirty 不需要每次都这样做
        // mark ComposedElement dirty when first elmtIds are added
        // do not need to do this every time
        this.markNeedUpdate();
      }
      stateMgmtConsole.debug(`${this.debugInfo__()}: viewPropertyHasChanged property: elmtIds that need re-render due to state variable change: ${this.debugInfoElmtIds(Array.from(dependentElmtIds))} .`);
    // 如果有recycleManager,将id代理后添加到dirtDescendantElementIds_中,否则直接添加到dirtDescendantElementIds_中
      for (const elmtId of dependentElmtIds) {
        if (this.hasRecycleManager()) {
          this.dirtDescendantElementIds_.add(this.recycleManager_.proxyNodeId(elmtId));
        } else {
          this.dirtDescendantElementIds_.add(elmtId);
        }
      }
      stateMgmtConsole.debug(`   ... updated full list of elmtIds that need re-render [${this.debugInfoElmtIds(Array.from(this.dirtDescendantElementIds_))}].`);
    } else {
      stateMgmtConsole.debug(`${this.debugInfo__()}: viewPropertyHasChanged: state variable change adds no elmtIds for re-render`);
      stateMgmtConsole.debug(`   ... unchanged full list of elmtIds that need re-render [${this.debugInfoElmtIds(Array.from(this.dirtDescendantElementIds_))}].`);
    }
  
    // 获取这个状态变量对应的Watch函数,执行
    let cb = this.watchedProps.get(varName)
    if (cb && typeof cb === 'function') {
      stateMgmtConsole.debug(`   ... calling @Watch function`);
      cb.call(this, varName);
    }

    this.restoreInstanceId();
    aceTrace.end();
    stateMgmtProfiler.end();
  }


  /**
通知特定elmtId的组件重新渲染,但是不执行watch函数
 *  inform that UINode with given elmtId needs rerender
 *  does NOT exec @Watch function.
 *  only used on V3 code path from ObserveV2.fireChange.
 *
 * FIXME will still use in the future?
 */
  public uiNodeNeedUpdateV3(elmtId: number): void {
    if (this.isFirstRender()) {
      return;
    }

    stateMgmtProfiler.begin(`ViewPU.uiNodeNeedUpdate ${this.debugInfoElmtId(elmtId)}`);

    if (!this.dirtDescendantElementIds_.size) { //  && !this runReuse_) {
      // mark ComposedElement dirty when first elmtIds are added
      // do not need to do this every time
      this.syncInstanceId();
      this.markNeedUpdate();
      this.restoreInstanceId();
    }
    if (this.hasRecycleManager()) {
      this.dirtDescendantElementIds_.add(this.recycleManager_.proxyNodeId(elmtId));
    } else {
      this.dirtDescendantElementIds_.add(elmtId);
    }
    stateMgmtConsole.debug(`${this.debugInfo__()}: uiNodeNeedUpdate: updated full list of elmtIds that need re-render [${this.debugInfoElmtIds(Array.from(this.dirtDescendantElementIds_))}].`);

    stateMgmtProfiler.end();
  }

  // 执行延迟更新
  private performDelayedUpdate(): void {
    if (!this.ownObservedPropertiesStore_.size) {
      return;
    }
    stateMgmtProfiler.begin('ViewPU.performDelayedUpdate');
    aceTrace.begin('ViewPU.performDelayedUpdate', this.constructor.name);
    stateMgmtConsole.debug(`${this.debugInfo__()}: performDelayedUpdate start ...`);
    this.syncInstanceId();
    // 遍历本组件拥有的状态变量,拿到依赖这个状态变量的自足缉拿,进行刷新
    for (const stateLinkPropVar of this.ownObservedPropertiesStore_) {
      const changedElmtIds = stateLinkPropVar.moveElmtIdsForDelayedUpdate();
      if (changedElmtIds) {
        const varName = stateLinkPropVar.info();
        if (changedElmtIds.size && !this.isFirstRender()) {
          for (const elmtId of changedElmtIds) {
            this.dirtDescendantElementIds_.add(elmtId);
          }
        }

        stateMgmtConsole.debug(`${this.debugInfo__()}: performDelayedUpdate: all elmtIds that need re-render [${Array.from(this.dirtDescendantElementIds_).toString()}].`);
    // 获取这个状态变量的watch,调用
        const cb = this.watchedProps.get(varName);
        if (cb) {
          stateMgmtConsole.debug(`   ... calling @Watch function`);
          cb.call(this, varName);
        }
      }
    } // for all ownStateLinkProps_
    this.restoreInstanceId();

    if (this.dirtDescendantElementIds_.size) {
      this.markNeedUpdate();
    }
    aceTrace.end()
    stateMgmtProfiler.end();
  }

  /**
从子组件的构造函数*调用的函数,以注册一个@Watch变量
   * Function to be called from the constructor of the sub component
   * to register a @Watch variable
变量名,而不是别名
   * @param propStr name of the variable. Note from @Provide and @Consume this is
   *      the variable name and not the alias!
   * @param callback application defined member function of sub-class
   */
  protected declareWatch(propStr: string, callback: (propName: string) => void): void {
    // 存起来
    this.watchedProps.set(propStr, callback);
  }

  /**
添加一个Provide状态变量
   * This View @Provide's a variable under given name
   * Call this function from the constructor of the sub class
   * @param providedPropName either the variable name or the alias defined as
   *        decorator param
   * @param store the backing store object for this variable (not the get/set variable!)
   */
  protected addProvidedVar<T>(providedPropName: string, store: ObservedPropertyAbstractPU<T>, allowOverride: boolean = false) {
    if (!allowOverride && this.findProvidePU(providedPropName)) {
      throw new ReferenceError(`${this.constructor.name}: duplicate @Provide property with name ${providedPropName}. Property with this name is provided by one of the ancestor Views already. @Provide override not allowed.`);
    }
    // 设置装饰器
    store.setDecoratorInfo('@Provide');
    // 存起来
    this.providedVars_.set(providedPropName, store);
  }

  /*
  从本组件开始递归查找Provided属性,没有就继续从父组件查找
    findProvidePU finds @Provided property recursively by traversing ViewPU's towards that of the UI tree root @Component:
    if 'this' ViewPU has a @Provide('providedPropName') return it, otherwise ask from its parent ViewPU.
  */
  public findProvidePU(providedPropName: string): ObservedPropertyAbstractPU<any> | undefined {
    return this.providedVars_.get(providedPropName) || (this.parent_ && this.parent_.findProvidePU(providedPropName));
  }

  /**
   * Method for the sub-class to call from its constructor for resolving
   *       a @Consume variable and initializing its backing store
   *       with the SyncedPropertyTwoWay<T> object created from the
   *       @Provide variable's backing store.
   * @param providedPropName the name of the @Provide'd variable.
   *     This is either the @Consume decorator parameter, or variable name.
   * @param consumeVarName the @Consume variable name (not the
   *            @Consume decorator parameter)
   * @returns initializing value of the @Consume backing store
   */
  protected initializeConsume<T>(providedPropName: string,
    consumeVarName: string): ObservedPropertyAbstractPU<T> {
    let providedVarStore: ObservedPropertyAbstractPU<any> = this.findProvidePU(providedPropName);
    if (providedVarStore === undefined) {
      throw new ReferenceError(`${this.debugInfo__()} missing @Provide property with name ${providedPropName}.
          Fail to resolve @Consume(${providedPropName}).`);
    }

    const factory = <T>(source: ObservedPropertyAbstract<T>) => {
      const result: ObservedPropertyAbstractPU<T> = new SynchedPropertyTwoWayPU<T>(source, this, consumeVarName);
      result.setDecoratorInfo('@Consume');
      stateMgmtConsole.debug(`The @Consume is instance of ${result.constructor.name}`);
      return result;
    };
    return providedVarStore.createSync(factory) as ObservedPropertyAbstractPU<T>;
  }


  /**

   * given the elmtId of a child or child of child within this custom component
   * remember this component needs a partial update
   * @param elmtId
   */
  public markElemenDirtyById(elmtId: number): void {
    // TODO ace-ets2bundle, framework, compiled apps need to update together
    // this function will be removed after a short transition period
    stateMgmtConsole.applicationError(`${this.debugInfo__()}: markElemenDirtyById no longer supported.
        Please update your ace-ets2bundle and recompile your application. Application error!`);
  }

  /**
   * For each recorded dirty Element in this custom component
   * run its update function
   *
   */
  public updateDirtyElements(): void {
    stateMgmtProfiler.begin('ViewPU.updateDirtyElements');
    do {
      stateMgmtConsole.debug(`${this.debugInfo__()}: updateDirtyElements (re-render): sorted dirty elmtIds: ${Array.from(this.dirtDescendantElementIds_).sort(ViewPU.compareNumber)}, starting ....`);

      // see which elmtIds are managed by this View
      // and clean up all book keeping for them
      this.purgeDeletedElmtIds();

      // process all elmtIds marked as needing update in ascending order.
      // ascending order ensures parent nodes will be updated before their children
      // prior cleanup ensure no already deleted Elements have their update func executed
      const dirtElmtIdsFromRootNode = Array.from(this.dirtDescendantElementIds_).sort(ViewPU.compareNumber);
      // if state changed during exec update lambda inside UpdateElement, then the dirty elmtIds will be added
      // to newly created this.dirtDescendantElementIds_ Set
      dirtElmtIdsFromRootNode.forEach(elmtId => {
        if (this.hasRecycleManager()) {
          this.UpdateElement(this.recycleManager_.proxyNodeId(elmtId));
        } else {
          this.UpdateElement(elmtId);
        }
        this.dirtDescendantElementIds_.delete(elmtId);
      });

      if (this.dirtDescendantElementIds_.size) {
        stateMgmtConsole.applicationError(`${this.debugInfo__()}: New UINode objects added to update queue while re-render! - Likely caused by @Component state change during build phase, not allowed. Application error!`);
      }
    } while (this.dirtDescendantElementIds_.size);
    stateMgmtConsole.debug(`${this.debugInfo__()}: updateDirtyElements (re-render) - DONE, dump of ViewPU in next lines`);
    stateMgmtProfiler.end();
  }

  // executed on first render only
  // kept for backward compatibility with old ace-ets2bundle
  public observeComponentCreation(compilerAssignedUpdateFunc: UpdateFunc): void {
    if (this.isDeleting_) {
      stateMgmtConsole.error(`View ${this.constructor.name} elmtId ${this.id__()} is already in process of destruction, will not execute observeComponentCreation `);
      return;
    }
    const updateFunc = (elmtId: number, isFirstRender: boolean): void => {
      stateMgmtConsole.debug(`${this.debugInfo__()}: ${isFirstRender ? `First render` : `Re-render/update`} start ....`);
      this.currentlyRenderedElmtIdStack_.push(elmtId);
      compilerAssignedUpdateFunc(elmtId, isFirstRender);
      this.currentlyRenderedElmtIdStack_.pop();
      stateMgmtConsole.debug(`${this.debugInfo__()}: ${isFirstRender ? `First render` : `Re-render/update`} - DONE ....`);
    }

    const elmtId = ViewStackProcessor.AllocateNewElmetIdForNextComponent();
    // in observeComponentCreation function we do not get info about the component name, in
    // observeComponentCreation2 we do.
    this.updateFuncByElmtId.set(elmtId, { updateFunc: updateFunc });
    // add element id -> owning ViewPU
    UINodeRegisterProxy.ElementIdToOwningViewPU_.set(elmtId, new WeakRef(this));
    try {
      updateFunc(elmtId, /* is first render */ true);
    } catch (error) {
      // avoid the incompatible change that move set function before updateFunc.
      this.updateFuncByElmtId.delete(elmtId);
      UINodeRegisterProxy.ElementIdToOwningViewPU_.delete(elmtId);
      stateMgmtConsole.applicationError(`${this.debugInfo__()} has error in update func: ${(error as Error).message}`);
      throw error;
    }
  }

  public observeComponentCreation2(compilerAssignedUpdateFunc: UpdateFunc, classObject: UIClassObject): void {
    if (this.isDeleting_) {
      stateMgmtConsole.error(`View ${this.constructor.name} elmtId ${this.id__()} is already in process of destruction, will not execute observeComponentCreation2 `);
      return;
    }
    // 组件名称
    const _componentName: string = (classObject && ('name' in classObject)) ? Reflect.get(classObject, 'name') as string : 'unspecified UINode';
    // pop函数
    const _popFunc: () => void = (classObject && 'pop' in classObject) ? classObject.pop! : (): void => { };
  // 更新函数
    const updateFunc = (elmtId: number, isFirstRender: boolean): void => {
      this.syncInstanceId();
      stateMgmtConsole.debug(`${this.debugInfo__()}: ${isFirstRender ? `First render` : `Re-render/update`} ${_componentName}[${elmtId}] ${!this.isViewV3 ? '(enable PU state observe) ' : ''} ${ConfigureStateMgmt.instance.needsV2Observe() ? '(enabled V2 state observe) ' : ''} - start ....`);

      ViewStackProcessor.StartGetAccessRecordingFor(elmtId);

      if (!this.isViewV3) {
        // Enable PU state tracking only in PU @Components
        this.currentlyRenderedElmtIdStack_.push(elmtId);
      }

      // if V2 @Observed/@Track used anywhere in the app (there is no more fine grained criteria),
      // enable V2 object deep observation
      // FIXME: A @Component should only use PU or V2 state, but ReactNative dynamic viewer uses both.
      if (this.isViewV3 || ConfigureStateMgmt.instance.needsV2Observe()) {
        // FIXME: like in V2 setting bindId_ in ObserveV2 does not work with 'stacked'
        // update + initial render calls, like in if and ForEach case, convert to stack as well
        ObserveV2.getObserve().startRecordDependencies(this, elmtId);
      }

      compilerAssignedUpdateFunc(elmtId, isFirstRender);
      if (!isFirstRender) {
        _popFunc();
      }

      let node = this.getNodeById(elmtId);
      if (node !== undefined) {
        (node as ArkComponent).cleanStageValue();
      }

      if (this.isViewV3 || ConfigureStateMgmt.instance.needsV2Observe()) {
        ObserveV2.getObserve().stopRecordDependencies();
      }
      if (!this.isViewV3) {
        this.currentlyRenderedElmtIdStack_.pop();
      }
      ViewStackProcessor.StopGetAccessRecording();

      stateMgmtConsole.debug(`${this.debugInfo__()}: ${isFirstRender ? `First render` : `Re-render/update`}  ${_componentName}[${elmtId}] - DONE ....`);
      this.restoreInstanceId();
    };
  // 生成一个唯一的elmtId
    const elmtId = ViewStackProcessor.AllocateNewElmetIdForNextComponent();
    // needs to move set before updateFunc.
    // make sure the key and object value exist since it will add node in attributeModifier during updateFunc.
    // 存储组件id到组件的更新函数
    this.updateFuncByElmtId.set(elmtId, { updateFunc: updateFunc, classObject: classObject });
    // add element id -> owning ViewPU
   // 存储组件id到组件自身
    UINodeRegisterProxy.ElementIdToOwningViewPU_.set(elmtId, new WeakRef(this));
    try {
      updateFunc(elmtId, /* is first render */ true);
    } catch (error) {
      // avoid the incompatible change that move set function before updateFunc.
      this.updateFuncByElmtId.delete(elmtId);
      UINodeRegisterProxy.ElementIdToOwningViewPU_.delete(elmtId);
      stateMgmtConsole.applicationError(`${this.debugInfo__()} has error in update func: ${(error as Error).message}`);
      throw error;
    }
    stateMgmtConsole.debug(`${this.debugInfo__()} is initial rendering elmtId ${elmtId}, tag: ${_componentName}, and updateFuncByElmtId size :${this.updateFuncByElmtId.size}`);
  }


  getOrCreateRecycleManager(): RecycleManager {
    if (!this.recycleManager_) {
      this.recycleManager_ = new RecycleManager;
    }
    return this.recycleManager_;
  }

  getRecycleManager(): RecycleManager {
    return this.recycleManager_;
  }

  hasRecycleManager(): boolean {
    return !(this.recycleManager_ === undefined);
  }

  initRecycleManager(): void {
    if (this.recycleManager_) {
      stateMgmtConsole.error(`${this.debugInfo__()}: init recycleManager multiple times. Internal error.`);
      return;
    }
    this.recycleManager_ = new RecycleManager;
  }
  rebuildUpdateFunc(elmtId, compilerAssignedUpdateFunc): void {
    const updateFunc = (elmtId, isFirstRender): void => {
      this.currentlyRenderedElmtIdStack_.push(elmtId);
      compilerAssignedUpdateFunc(elmtId, isFirstRender);
      this.currentlyRenderedElmtIdStack_.pop();
    };
    if (this.updateFuncByElmtId.has(elmtId)) {
      this.updateFuncByElmtId.set(elmtId, { updateFunc: updateFunc });
    }
  }

  /**
   * @function observeRecycleComponentCreation
   * @description custom node recycle creation
   * @param name custom node name
   * @param recycleUpdateFunc custom node recycle update which can be converted to a normal update function
   * @return void
   */
  public observeRecycleComponentCreation(name: string, recycleUpdateFunc: RecycleUpdateFunc): void {
    // convert recycle update func to update func
    const compilerAssignedUpdateFunc: UpdateFunc = (element, isFirstRender) => {
      recycleUpdateFunc(element, isFirstRender, undefined);
    };
    let node: ViewPU;
    // if there is no suitable recycle node, run a normal creation function.
    if (!this.hasRecycleManager() || !(node = this.getRecycleManager().popRecycleNode(name))) {
      stateMgmtConsole.debug(`${this.constructor.name}[${this.id__()}]: cannot init node by recycle, crate new node`);
      this.observeComponentCreation(compilerAssignedUpdateFunc);
      return;
    }

    // if there is a suitable recycle node, run a recycle update function.
    const newElmtId: number = ViewStackProcessor.AllocateNewElmetIdForNextComponent();
    const oldElmtId: number = node.id__();
    this.recycleManager_.updateNodeId(oldElmtId, newElmtId);
    this.addChild(node);
    this.rebuildUpdateFunc(oldElmtId, compilerAssignedUpdateFunc);
    recycleUpdateFunc(oldElmtId, /* is first render */ true, node);
  }
  // 组件重用 是指用状态变量更新同一个组件
  aboutToReuseInternal() {
    this.runReuse_ = true;
    stateMgmtTrace.scopedTrace(() => {
      if (this.paramsGenerator_ && typeof this.paramsGenerator_ === 'function') {
        const params = this.paramsGenerator_();
        this.updateStateVars(params);
        this.aboutToReuse(params);
      }
    }, "aboutToReuse", this.constructor.name);
  // 组件重用时,遍历拥有的状态变量,更新子组件
    for (const stateLinkPropVar of this.ownObservedPropertiesStore_) {
      const changedElmtIds =  stateLinkPropVar.moveElmtIdsForDelayedUpdate(true);
      if (changedElmtIds) {
        if (changedElmtIds.size && !this.isFirstRender()) {
          for (const elmtId of changedElmtIds) {
            this.dirtDescendantElementIds_.add(elmtId);
          }
        }
      }
    }
    this.updateDirtyElements();
    this.childrenWeakrefMap_.forEach((weakRefChild) => {
      const child = weakRefChild.deref();
      if (child) {
        if (child instanceof ViewPU) {
          child.aboutToReuseInternal();
        } else {
          // FIXME fix for mixed V2 - V3 Hierarchies
          throw new Error('aboutToReuseInternal: Recycle not implemented for ViewV2, yet');
        }
      } // if child
    });
    this.runReuse_ = false;
  }
  // 复用
  aboutToRecycleInternal() {
    this.runReuse_ = true;
    stateMgmtTrace.scopedTrace(() => {
      this.aboutToRecycle();
    }, 'aboutToRecycle', this.constructor.name);
    this.childrenWeakrefMap_.forEach((weakRefChild) => {
      const child = weakRefChild.deref();
      if (child) {
        if (child instanceof ViewPU) {
          child.aboutToRecycleInternal();
        } else {
          // FIXME fix for mixed V2 - V3 Hierarchies
          throw new Error('aboutToRecycleInternal: Recycle not yet implemented for ViewV2');
        }
      } // if child
    });
    this.runReuse_ = false;
  }

  // add current JS object to it's parent recycle manager
  public recycleSelf(name: string): void {

    if (this.getParent() && this.getParent() instanceof ViewPU && !(this.getParent() as ViewPU).isDeleting_) {
      const parentPU : ViewPU = this.getParent() as ViewPU;
      parentPU.getOrCreateRecycleManager().pushRecycleNode(name, this);
      this.parent_.removeChild(this);
      this.setActiveInternal(false);
    } else {
      this.resetRecycleCustomNode();
      stateMgmtConsole.error(`${this.constructor.name}[${this.id__()}]: recycleNode must have a parent`);
    }
  }

  public UpdateLazyForEachElements(elmtIds: Array<number>): void {
    if (!Array.isArray(elmtIds)) {
      return;
    }
    Array.from(elmtIds).sort(ViewPU.compareNumber).forEach((elmtId: number) => {
      const entry: UpdateFuncRecord | undefined = this.updateFuncByElmtId.get(elmtId);
      const updateFunc: UpdateFunc = entry ? entry.getUpdateFunc() : undefined;
      if (typeof updateFunc !== 'function') {
        stateMgmtConsole.debug(`${this.debugInfo__()}: update function of elmtId ${elmtId} not found, internal error!`);
      } else {
        this.isRenderInProgress = true;
        updateFunc(elmtId, false);
        this.finishUpdateFunc(elmtId);
        this.isRenderInProgress = false;
      }
    })
  }

  /**
创建@StorageLink和@LocalStorageLink的状态变量
     * CreateStorageLink and CreateStorageLinkPU are used by the implementation of @StorageLink and
     * @LocalStotrageLink in full update and partial update solution respectively.
     * These are not part of the public AppStorage API , apps should not use.
在LocalStorage中的键
     * @param storagePropName - key in LocalStorage LocalStorage中的key
在LocalStorage中创建新属性时使用的值
     * @param defaultValue - value to use when creating a new prop in the LocalStotage
拥有@StorageLink/@LocalStorageLink变量的视图/视图PU
     * @param owningView - the View/ViewPU owning the @StorageLink/@LocalStorageLink variable
StorageLink/@LocalStorageLink变量名
     * @param viewVariableName -  @StorageLink/@LocalStorageLink variable name
     * @returns SynchedPropertySimple/ObjectTwoWay/PU
     */
  public createStorageLink<T>(storagePropName: string, defaultValue: T, viewVariableName: string): ObservedPropertyAbstractPU<T> {
    const appStorageLink = AppStorage.__createSync<T>(storagePropName, defaultValue,
      <T>(source: ObservedPropertyAbstract<T>) => (source === undefined)
        ? undefined
        : new SynchedPropertyTwoWayPU<T>(source, this, viewVariableName)
    ) as ObservedPropertyAbstractPU<T>;
    appStorageLink.setDecoratorInfo('@StorageLink');
    return appStorageLink;
  }

  public createStorageProp<T>(storagePropName: string, defaultValue: T, viewVariableName: string): ObservedPropertyAbstractPU<T> {
    const appStorageProp = AppStorage.__createSync<T>(storagePropName, defaultValue,
      <T>(source: ObservedPropertyAbstract<T>) => (source === undefined)
        ? undefined
        : new SynchedPropertyOneWayPU<T>(source, this, viewVariableName)
    ) as ObservedPropertyAbstractPU<T>;
    appStorageProp.setDecoratorInfo('@StorageProp');
    return appStorageProp;
  }

  public createLocalStorageLink<T>(storagePropName: string, defaultValue: T,
    viewVariableName: string): ObservedPropertyAbstractPU<T> {
    const localStorageLink = this.localStorage_.__createSync<T>(storagePropName, defaultValue,
      <T>(source: ObservedPropertyAbstract<T>) => (source === undefined)
        ? undefined
        : new SynchedPropertyTwoWayPU<T>(source, this, viewVariableName)
    ) as ObservedPropertyAbstractPU<T>;
    localStorageLink.setDecoratorInfo('@LocalStorageLink');
    return localStorageLink;
  }

  public createLocalStorageProp<T>(storagePropName: string, defaultValue: T,
    viewVariableName: string): ObservedPropertyAbstractPU<T> {
    const localStorageProp = this.localStorage_.__createSync<T>(storagePropName, defaultValue,
      <T>(source: ObservedPropertyAbstract<T>) => (source === undefined)
        ? undefined
        : new SynchedPropertyObjectOneWayPU<T>(source, this, viewVariableName)
    ) as ObservedPropertyAbstractPU<T>;
    localStorageProp.setDecoratorInfo('@LocalStorageProp');
    return localStorageProp;
  }

  /**
   * onDumpInfo is used to process commands delivered by the hidumper process
   * @param commands -  list of commands provided in the shell
   * @returns void
   */
  protected onDumpInfo(commands: string[]): void {

    let dfxCommands: DFXCommand[] = this.processOnDumpCommands(commands);

    dfxCommands.forEach((command) => {
      let view: ViewPU = undefined;
      if (command.viewId) {
        view = this.findViewPUInHierarchy(command.viewId);
        if (!view) {
          DumpLog.print(0, `\nTarget view: ${command.viewId} not found for command: ${command.what}\n`);
          return;
        }
      } else {
        view = this;
        command.viewId = view.id__();
      }
      switch (command.what) {
        case '-dumpAll':
          view.printDFXHeader('ViewPU Info', command);
          DumpLog.print(0, view.debugInfoView(command.isRecursive));
          break;
        case '-viewHierarchy':
          view.printDFXHeader('ViewPU Hierarchy', command);
          DumpLog.print(0, view.debugInfoViewHierarchy(command.isRecursive));
          break;
        case '-stateVariables':
          view.printDFXHeader('ViewPU State Variables', command);
          DumpLog.print(0, view.debugInfoStateVars());
          break;
        case '-registeredElementIds':
          view.printDFXHeader('ViewPU Registered Element IDs', command);
          DumpLog.print(0, view.debugInfoUpdateFuncByElmtId(command.isRecursive));
          break;
        case '-dirtyElementIds':
          view.printDFXHeader('ViewPU Dirty Registered Element IDs', command);
          DumpLog.print(0, view.debugInfoDirtDescendantElementIds(command.isRecursive));
          break;
        case '-inactiveComponents':
          view.printDFXHeader('List of Inactive Components', command);
          DumpLog.print(0, view.debugInfoInactiveComponents());
          break;
        case '-profiler':
          view.printDFXHeader('Profiler Info', command);
          view.dumpReport();
          this.sendStateInfo('{}');
          break;
        default:
          DumpLog.print(0, `\nUnsupported JS DFX dump command: [${command.what}, viewId=${command.viewId}, isRecursive=${command.isRecursive}]\n`);
      }
    })
  }

  private printDFXHeader(header: string, command: DFXCommand): void {
    let length: number = 50;
    let remainder: number = length - header.length < 0 ? 0 : length - header.length;
    DumpLog.print(0, `\n${'-'.repeat(remainder / 2)}${header}${'-'.repeat(remainder / 2)}`);
    DumpLog.print(0, `[${command.what}, viewId=${command.viewId}, isRecursive=${command.isRecursive}]\n`);
  }

  private processOnDumpCommands(commands: string[]): DFXCommand[] {
    let isFlag: Function = (param: string): boolean => {
      return '-r'.match(param) != null || param.startsWith('-viewId=');
    }

    let dfxCommands: DFXCommand[] = [];

    for (var i: number = 0; i < commands.length; i++) {
      let command = commands[i];
      if (isFlag(command)) {
        if (command.startsWith('-viewId=')) {
          let dfxCommand: DFXCommand = dfxCommands[dfxCommands.length - 1];
          if (dfxCommand) {
            let input: string[] = command.split('=');
            if (input[1]) {
              let viewId: number = Number.parseInt(input[1]);
              dfxCommand.viewId = Number.isNaN(viewId) ? UINodeRegisterProxy.notRecordingDependencies : viewId;
            }
          }
        } else if (command.match('-r')) {
          let dfxCommand: DFXCommand = dfxCommands[dfxCommands.length - 1];
          if (dfxCommand) {
            dfxCommand.isRecursive = true;
          }
        }
      } else {
        dfxCommands.push({
          what: command,
          viewId: undefined,
          isRecursive: false,
        });
      }
    }
    return dfxCommands;
  }

  public findViewPUInHierarchy(id: number): ViewPU {
    let weakChild = this.childrenWeakrefMap_.get(id);
    if (weakChild) {
      const child = weakChild.deref();
      // found child with id, is it a ViewPU?
      return (child instanceof ViewPU) ? child : undefined;
    }

    // did not find, continue searching
    let retVal: ViewPU = undefined;
    for (const [key, value] of this.childrenWeakrefMap_.entries()) {
      retVal = value.deref().findViewPUInHierarchy(id);
      if (retVal) {
        break;
      }
    }
    return retVal;
  }

  private debugInfoView(recursive: boolean = false): string {
    return this.debugInfoViewInternal(recursive);
  }

  private debugInfoViewInternal(recursive: boolean = false): string {
    let retVal: string = `@Component\n${this.constructor.name}[${this.id__()}]`;
    retVal += `\n\nView Hierarchy:\n${this.debugInfoViewHierarchy(recursive)}`;
    retVal += `\n\nState variables:\n${this.debugInfoStateVars()}`;
    retVal += `\n\nRegistered Element IDs:\n${this.debugInfoUpdateFuncByElmtId(recursive)}`;
    retVal += `\n\nDirty Registered Element IDs:\n${this.debugInfoDirtDescendantElementIds(recursive)}`;
    return retVal;
  }

  private debugInfoDirtDescendantElementIds(recursive: boolean = false): string {
    return this.debugInfoDirtDescendantElementIdsInternal(0, recursive, { total: 0 });
  }

  public debugInfoDirtDescendantElementIdsInternal(depth: number = 0, recursive: boolean = false, counter: ProfileRecursionCounter): string {
    let retVaL: string = `\n${'  '.repeat(depth)}|--${this.constructor.name}[${this.id__()}]: {`;
    this.dirtDescendantElementIds_.forEach((value) => {
      retVaL += `${value}, `;
    });
    counter.total += this.dirtDescendantElementIds_.size;
    retVaL += `\n${'  '.repeat(depth + 1)}}[${this.dirtDescendantElementIds_.size}]`;
    if (recursive) {
      this.childrenWeakrefMap_.forEach((value, key, map) => {
        retVaL += value.deref()?.debugInfoDirtDescendantElementIdsInternal(depth + 1, recursive, counter);
      })
    }

    if (recursive && depth == 0) {
      retVaL += `\nTotal: ${counter.total}`;
    }
    return retVaL;
  }

  /**
   * on first render create a new Instance of Repeat
   * on re-render connect to existing instance
   * @param arr
   * @returns
   */
  public __mkRepeatAPI: <I>(arr: Array<I>) => RepeatAPI<I> = <I>(arr: Array<I>): RepeatAPI<I> => {
    // factory is for future extensions, currently always return the same
    const elmtId = this.getCurrentlyRenderedElmtId();
    let repeat = this.elmtId2Repeat_.get(elmtId) as __RepeatPU<I>
    if (!repeat) {
        repeat = new __RepeatPU<I>(this, arr);
        this.elmtId2Repeat_.set(elmtId, repeat);
    } else {
        repeat.updateArr(arr)
    }

    return repeat;
  }
}

状态变量相关

watchedProps

private watchedProps: Map<string, (propName: string) => void> = new Map<string, (propName: string) => void>();
以Map形式存储@Watch声明的函数,key是传入Watch的字符串函数名,value是对应的函数地址

providedVars_

protected providedVars_: Map<string, ObservedPropertyAbstractPU> = new Map<string, ObservedPropertyAbstractPU>();
以Map形式存储本组件以及祖先组件中声明的@Provided状态变量,key是传入@Provided的别名(没有别名时使用变量名),value是状态变量

localStoragebackStore_

protected localStoragebackStore_: LocalStorage = undefined;
存储组件的LocalStorage,如果传递了storage就使用传递的storage,否则,先查看父类有没有storage,有就取父类的storage,否则创建一个默认的storage。
也就是说组件一定有一个storage,只是我们不一定能访问

ownObservedPropertiesStore__

private ownObservedPropertiesStore__?: Set;
本组件内声明的状态变量

createStorageLink与createLocalStorageLink

在这里插入图片描述

AppStorage是LocalStorage的一个子类,并且是一个单例
在这里插入图片描述
在这里插入图片描述

createStorageProp与createLocalStorageProp

在这里插入图片描述

更新相关

updateFuncByElmtId

它是一个类UpdateFuncsByElmtId,其实这个类内部也是使用的Map存储,key是组件id,value是包装后的更新函数

childrenWeakrefMap_

以Map形式存储本组件的子组件,key是组件id,value是组件实例

总结

1.ArkTS中所有的自定义组件转换成TS后都是一个继承自ViewPU的子类
2.所有的组件的创建都是通过observeComponentCreation2方法完成
3.组件的创建是一个出入栈的过程,Create方法入栈,Pop方法出栈,栈为空时将该节点挂载到父节点上

鸿蒙中也存在三棵树,可以看官网的一张图 developer.huawei.com/consumer/cn…
在这里插入图片描述

写在最后

●如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我两个小忙:
●点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
●关注小编,同时可以期待后续文章ing ,不定期分享原创知识。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值