鸿蒙ACE-ArkUI构建(二)、渲染控制和构建过程

524 阅读20分钟

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出栈,最终组成组件树

image.png

一帧的核心绘制流程

image.png

  1. Component树经过测算后转换成FrameNode树,再经过布局、绘制操作转换成RSNode
  2. RSNode 录制指令,交给RSCanvasNode转换成渲染指令,然后通过IPC发送给RenderService再经由GPU、CPU绘制出来

if/else 转换前后

image.png

一、If 是一个单独的组件,也可以通过Create、Pop创建和销毁

image.png

二、有多少个分支,就会创建多少个 ifElseBranchUpdateFunction,它的第一个参数是唯一的一个数字,从0递增,第二个参数是一个箭头函数,用于创建组件

image.png

ForEach转换前后

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

developer.huawei.com/consumer/cn…

image.png

一、ForEach 是一个单独的组件,也可以通过Create、Pop创建和销毁

image.png

二、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 转换前后

image.png

一、LazyForEach 是一个单独的组件,也可以通过Create、Pop创建和销毁

create参数中的builder和idfunc都是我们生成的函数

image.png

import 转换前后

image.png

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

自定义组件 转化前后

  1. 自定义组件最终都会转换为 ViewPU的子类
  2. 自定义组件的参数 会被集合到一个interface定义中,命名参数传递也是基于此实现
  3. 普通变量不做改变,状态变量会被重写为getter和setter 同时生成双下划线开头的状态类

image.png 在组件构建的时候就会通过传入的参数初始化对应的私有状态变量

image.png

系统组件

void RegisterAllModule(BindingTarget globalObj, void* nativeEngine)

系统组件和自定义组件不同,每一个系统组件都绑定了一个对应的C++类

所有的组件都通过 RegisterAllModule 进行了注册。

image.png

static const std::unordered_map<std::string, std::function<void(BindingTarget)>> bindFuncs =

系统组件和TS类的映射关系如下

image.png

以Text为例

首先在Bind方法内声明了类名为Text,然后将一些属性绑定到了C++底层的方法

image.png

最后继承并绑定globalObj的属性,也就是所有组件的公共属性

image.png

JSClass::Declare

C++底层是通过模板类来创建的组件类。生成的类有静态方法、对象方法、getter/setter以及类方法等

image.png

void JsiClass::StaticMethod

image.png

JSClass::InheritAndBind(globalObj)

image.png

initialRender:构建UI树

observeComponentCreation2

每个组件的创建都是通过 observeComponentCreation2 完成的。

image.png

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

image.png

create

TextModel::Create

看一下Text的create方法,最终实现调用了 TextModel::GetInstance()->Create(data);

image.png

TextModelNG::Create

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

image.png

很简单,就是一个入栈操作

image.png

pop

JSContainerBase Pop方法

Pop方法位于JSText的父类 JSContainerBase 中

image.png

image.png

image.png

ViewStackModel::PopContainer

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

在节点是AtomicNode的时候一直出栈,直到栈中只保留一个节点

image.png

isAtomicNode也有解释,是指button、image、自定义组件等等,只有Create函数没有Pop函数

image.png

ViewStackProcessor::Pop

image.png

ViewStackProcessor::Finish

image.png

小结

  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<ObservedPropertyAbstractPU>;

本组件内声明的状态变量

createStorageLink与createLocalStorageLink

image.png

AppStorage是LocalStorage的一个子类,并且是一个单例

image.png

image.png

createStorageProp与createLocalStorageProp

image.png

更新相关

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…

image.png

参考资料

  1. 声明式范式的语法编译转换,语法验证等 https://gitee.com/openharmony/developtools_ace_ets2bundle
  2. ArkUI引擎 https://gitee.com/openharmony/arkui_ace_engine
  3. ArkUIX gitee.com/arkui-x
  4. openharmony文档 https://gitee.com/openharmony/docs/tree/master/zh-cn/readme
  5. flutter android 鸿蒙 linux apple图形渲染比较 https://zhuanlan.zhihu.com/p/622375832
  6. 渲染控制概述 developer.huawei.com/consumer/cn…