diff --git a/libs/horizon/src/renderer/ErrorHandler.ts b/libs/horizon/src/renderer/ErrorHandler.ts index 3c3305c1..991ef861 100644 --- a/libs/horizon/src/renderer/ErrorHandler.ts +++ b/libs/horizon/src/renderer/ErrorHandler.ts @@ -71,7 +71,7 @@ export function handleRenderThrowError( // vNode抛出了异常,标记Interrupted中断 FlagUtils.markInterrupted(sourceVNode); // dirtyNodes 不再有效 - sourceVNode.dirtyNodes = []; + sourceVNode.dirtyNodes = null; // error是个promise if (error !== null && typeof error === 'object' && typeof error.then === 'function') { diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts index 3c9b729b..020b58b2 100644 --- a/libs/horizon/src/renderer/TreeBuilder.ts +++ b/libs/horizon/src/renderer/TreeBuilder.ts @@ -57,10 +57,23 @@ function resetProcessingVariables(startUpdateVNode: VNode) { // 收集有变化的节点,在submit阶段继续处理 function collectDirtyNodes(vNode: VNode, parent: VNode): void { // 将子树和此vNode的所有效果附加到父树的效果列表中,子项的完成顺序会影响副作用顺序。 - parent.dirtyNodes.push(...vNode.dirtyNodes); + const dirtyNodes = vNode.dirtyNodes; + if (dirtyNodes !== null && dirtyNodes.length) { + if (parent.dirtyNodes === null) { + parent.dirtyNodes = [...vNode.dirtyNodes]; + } else { + parent.dirtyNodes.push(...vNode.dirtyNodes); + } + dirtyNodes.length = 0; + vNode.dirtyNodes = null; + } if (FlagUtils.hasAnyFlag(vNode)) { - parent.dirtyNodes.push(vNode); + if (parent.dirtyNodes === null) { + parent.dirtyNodes = [vNode]; + } else { + parent.dirtyNodes.push(vNode); + } } } diff --git a/libs/horizon/src/renderer/UpdateHandler.ts b/libs/horizon/src/renderer/UpdateHandler.ts index d00f3ce9..a2b55485 100644 --- a/libs/horizon/src/renderer/UpdateHandler.ts +++ b/libs/horizon/src/renderer/UpdateHandler.ts @@ -72,7 +72,11 @@ function calcState( function collectCallbacks(vNode: VNode, update: Update) { if (update.callback !== null) { FlagUtils.markCallback(vNode); - vNode.stateCallbacks.push(update.callback); + if (vNode.stateCallbacks === null) { + vNode.stateCallbacks = [update.callback]; + } else { + vNode.stateCallbacks.push(update.callback); + } } } diff --git a/libs/horizon/src/renderer/components/context/Context.ts b/libs/horizon/src/renderer/components/context/Context.ts index bcbc4f83..4052a0ed 100644 --- a/libs/horizon/src/renderer/components/context/Context.ts +++ b/libs/horizon/src/renderer/components/context/Context.ts @@ -4,17 +4,19 @@ import {throwNotInFuncError} from '../../hooks/BaseHook'; // 重置依赖 export function resetDepContexts(vNode: VNode): void { - vNode.depContexts = []; + vNode.depContexts = null; } // 收集依赖 function collectDeps(vNode: VNode, context: ContextType) { const depContexts = vNode.depContexts; - if (!depContexts.length) { + if (depContexts === null) { + vNode.depContexts = [context]; + } else { vNode.isDepContextChange = false; - } - if (!depContexts.includes(context)) { - depContexts.push(context); + if (!depContexts.includes(context)) { + depContexts.push(context); + } } } diff --git a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts index 797687b5..0d65c816 100644 --- a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts +++ b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts @@ -27,6 +27,10 @@ function isNoKeyFragment(child: any) { // 清除单个节点 function deleteVNode(parentNode: VNode, delVNode: VNode): void { FlagUtils.setDeletion(delVNode); + if (parentNode.dirtyNodes === null) { + parentNode.dirtyNodes = [delVNode]; + return; + } parentNode.dirtyNodes.push(delVNode); } diff --git a/libs/horizon/src/renderer/render/ContextProvider.ts b/libs/horizon/src/renderer/render/ContextProvider.ts index c31a9ff4..c3c287d8 100644 --- a/libs/horizon/src/renderer/render/ContextProvider.ts +++ b/libs/horizon/src/renderer/render/ContextProvider.ts @@ -50,7 +50,7 @@ function handleContextChange(processing: VNode, context: ContextType): void // 从vNode开始遍历 travelVNodeTree(vNode, node => { const depContexts = node.depContexts; - if (depContexts.length) { + if (depContexts && depContexts.length) { isMatch = matchDependencies(depContexts, context, node) ?? isMatch; } }, node => diff --git a/libs/horizon/src/renderer/submit/HookEffectHandler.ts b/libs/horizon/src/renderer/submit/HookEffectHandler.ts index b6706389..f1811d93 100644 --- a/libs/horizon/src/renderer/submit/HookEffectHandler.ts +++ b/libs/horizon/src/renderer/submit/HookEffectHandler.ts @@ -27,23 +27,24 @@ export function isSchedulingEffects() { export function callUseEffects(vNode: VNode) { const effectList: EffectList = vNode.effectList; - - effectList.forEach(effect => { - const {effectConstant} = effect; - if ( - (effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect && - (effectConstant & EffectConstant.DepsChange) !== EffectConstant.NoEffect - ) { - hookEffects.push(effect); - hookRemoveEffects.push(effect); - - // 异步调用 - if (!isScheduling) { - isScheduling = true; - runAsync(runAsyncEffects); + if (effectList !== null) { + effectList.forEach(effect => { + const {effectConstant} = effect; + if ( + (effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect && + (effectConstant & EffectConstant.DepsChange) !== EffectConstant.NoEffect + ) { + hookEffects.push(effect); + hookRemoveEffects.push(effect); + + // 异步调用 + if (!isScheduling) { + isScheduling = true; + runAsync(runAsyncEffects); + } } - } - }); + }); + } } export function runAsyncEffects() { @@ -85,23 +86,24 @@ export function runAsyncEffects() { // 在销毁vNode的时候调用remove export function callEffectRemove(vNode: VNode) { const effectList: EffectList = vNode.effectList; - - effectList.forEach(effect => { - const {removeEffect, effectConstant} = effect; - - if (removeEffect !== undefined) { - if ((effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect) { // 如果是useEffect,就异步调用 - hookRemoveEffects.push(effect); - - if (!isScheduling) { - isScheduling = true; - runAsync(runAsyncEffects); + if (effectList !== null) { + effectList.forEach(effect => { + const {removeEffect, effectConstant} = effect; + + if (removeEffect !== undefined) { + if ((effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect) { // 如果是useEffect,就异步调用 + hookRemoveEffects.push(effect); + + if (!isScheduling) { + isScheduling = true; + runAsync(runAsyncEffects); + } + } else { // 是useLayoutEffect,直接执行 + removeEffect(); } - } else { // 是useLayoutEffect,直接执行 - removeEffect(); } - } - }); + }); + } } // 同步执行UseLayoutEffect的remove @@ -109,26 +111,29 @@ export function callUseLayoutEffectRemove(vNode: VNode) { const effectList: EffectList = vNode.effectList; const layoutLabel = EffectConstant.LayoutEffect | EffectConstant.DepsChange; - effectList.forEach(effect => { - if ((effect.effectConstant & layoutLabel) === layoutLabel) { - const remove = effect.removeEffect; - effect.removeEffect = undefined; - if (typeof remove === 'function') { - remove(); + if (effectList !== null) { + effectList.forEach(effect => { + if ((effect.effectConstant & layoutLabel) === layoutLabel) { + const remove = effect.removeEffect; + effect.removeEffect = undefined; + if (typeof remove === 'function') { + remove(); + } } - } - }); + }); + } } // 同步执行UseLayoutEffect export function callUseLayoutEffectCreate(vNode: VNode) { const effectList: EffectList = vNode.effectList; - - const layoutLabel = EffectConstant.LayoutEffect | EffectConstant.DepsChange; - effectList.forEach(effect => { - if ((effect.effectConstant & layoutLabel) === layoutLabel) { - const create = effect.effect; - effect.removeEffect = create(); - } - }); + if (effectList !== null) { + const layoutLabel = EffectConstant.LayoutEffect | EffectConstant.DepsChange; + effectList.forEach(effect => { + if ((effect.effectConstant & layoutLabel) === layoutLabel) { + const create = effect.effect; + effect.removeEffect = create(); + } + }); + } } diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index be4152d1..354a179e 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -72,13 +72,14 @@ function callBeforeSubmitLifeCycles( // 调用vNode.stateCallbacks function callStateCallback(vNode: VNode, obj: any): void { const stateCallbacks = vNode.stateCallbacks; - vNode.stateCallbacks = []; - - stateCallbacks.forEach(callback => { - if (typeof callback === 'function') { - callback.call(obj); - } - }); + vNode.stateCallbacks = null; + if (stateCallbacks !== null) { + stateCallbacks.forEach(callback => { + if (typeof callback === 'function') { + callback.call(obj); + } + }); + } } // 调用界面变化后的生命周期 diff --git a/libs/horizon/src/renderer/submit/Submit.ts b/libs/horizon/src/renderer/submit/Submit.ts index e222564f..30fee9d8 100644 --- a/libs/horizon/src/renderer/submit/Submit.ts +++ b/libs/horizon/src/renderer/submit/Submit.ts @@ -40,11 +40,15 @@ export function submitToRender(treeRoot) { if (FlagUtils.hasAnyFlag(startVNode)) { // 把自己加上 - startVNode.dirtyNodes.push(startVNode); + if (startVNode.dirtyNodes === null) { + startVNode.dirtyNodes = [startVNode]; + } else { + startVNode.dirtyNodes.push(startVNode); + } } const dirtyNodes = startVNode.dirtyNodes; - if (dirtyNodes.length) { + if (dirtyNodes !== null && dirtyNodes.length) { const preMode = copyExecuteMode(); changeMode(InRender, true); @@ -60,7 +64,9 @@ export function submitToRender(treeRoot) { // after submit阶段 afterSubmit(dirtyNodes); - setExecuteMode(preMode) + setExecuteMode(preMode); + dirtyNodes.length = 0; + startVNode.dirtyNodes = null; } if (isSchedulingEffects()) { diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index e5a848de..8ce6d94b 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -25,17 +25,17 @@ export class VNode { suspensePromises: any = null; // suspense组件的promise列表 changeList: any = null; // DOM的变更列表 - effectList: any[] = []; // useEffect 的更新数组 + effectList: any[] | null = null; // useEffect 的更新数组 updates: any[] | null = null; // TreeRoot和ClassComponent使用的更新数组 - stateCallbacks: any[] = []; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组 + stateCallbacks: any[] | null = null; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组 isForceUpdate: boolean = false; // 是否使用强制更新 state: any = null; // ClassComponent和TreeRoot的状态 - hooks: Array> = []; // 保存hook + hooks: Array> | null = null; // 保存hook suspenseChildStatus: string = ''; // Suspense的Children是否显示 - depContexts: Array> = []; // FunctionComponent和ClassComponent对context的依赖列表 + depContexts: Array> | null = null; // FunctionComponent和ClassComponent对context的依赖列表 isDepContextChange: boolean = false; // context是否变更 - dirtyNodes: Array = []; // 需要改动的节点数组 + dirtyNodes: Array | null = null; // 需要改动的节点数组 shouldUpdate: boolean = false; childShouldUpdate: boolean = false; outerDom: any; @@ -65,7 +65,7 @@ export class VNode { clearChild: VNode | null = null; // one tree相关属性 isCreated: boolean = true; - oldHooks: Array> = []; // 保存上一次执行的hook + oldHooks: Array> | null = []; // 保存上一次执行的hook oldState: any = null; oldRef: RefType | ((handle: any) => void) | null = null; suspenseChildThrow = false; @@ -74,7 +74,7 @@ export class VNode { suspenseDidCapture: boolean = false; // suspense是否捕获了异常 promiseResolve: boolean = false; // suspense的promise是否resolve - path: Array = []; // 保存从根到本节点的路径 + path: string = ''; // 保存从根到本节点的路径 toUpdateNodes: Set | null = null; // 保存要更新的节点 belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用 diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts index 11abe1b1..2d6d3bb2 100644 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts @@ -78,7 +78,7 @@ export function updateVNode(vNode: VNode, vNodeProps?: any): VNode { vNode.oldRef = vNode.ref; FlagUtils.setNoFlags(vNode); - vNode.dirtyNodes = []; + vNode.dirtyNodes = null; vNode.isCreated = false; return vNode; @@ -143,7 +143,7 @@ export function createUndeterminedVNode(type, key, props) { export function createTreeRootVNode(container) { const vNode = newVirtualNode(TreeRoot, null, null, container); - vNode.path.push(0); + vNode.path += 0; createUpdateArray(vNode); return vNode; } @@ -155,7 +155,7 @@ export function createVNode(tag: VNodeTag | string, ...secondArg) { case TreeRoot: // 创建treeRoot vNode = newVirtualNode(TreeRoot, null, null, secondArg[0]); - vNode.path.push(0); + vNode.path += 0; createUpdateArray(vNode); break; @@ -165,7 +165,7 @@ export function createVNode(tag: VNodeTag | string, ...secondArg) { } export function updateVNodePath(vNode: VNode) { - vNode.path = [...vNode.parent.path, vNode.cIndex]; + vNode.path = vNode.parent.path + vNode.cIndex; } export function createVNodeFromElement(element: JSXElement): VNode { diff --git a/libs/horizon/src/renderer/vnode/VNodeUtils.ts b/libs/horizon/src/renderer/vnode/VNodeUtils.ts index dc38b93e..82ad3ec8 100644 --- a/libs/horizon/src/renderer/vnode/VNodeUtils.ts +++ b/libs/horizon/src/renderer/vnode/VNodeUtils.ts @@ -79,28 +79,24 @@ export function travelVNodeTree( export function clearVNode(vNode: VNode) { vNode.child = null; vNode.next = null; - vNode.depContexts = []; - vNode.dirtyNodes = []; + vNode.depContexts = null; + vNode.dirtyNodes = null; vNode.state = null; - vNode.hooks = []; - vNode.suspenseChildStatus = ''; + vNode.hooks = null; vNode.props = null; vNode.parent = null; vNode.suspensePromises = null; vNode.changeList = null; - vNode.effectList = []; + vNode.effectList = null; vNode.updates = null; vNode.realNode = null; vNode.oldProps = null; - vNode.oldHooks = []; + vNode.oldHooks = null; vNode.oldState = null; vNode.oldRef = null; - vNode.suspenseChildThrow = false; - vNode.oldSuspenseChildStatus = ''; vNode.oldChild = null; - vNode.path = []; vNode.toUpdateNodes = null; vNode.belongClassVNode = null;