From b0c3086a774b54e0ac52bb43471743f6ce9a31a6 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 19:27:00 +0800 Subject: [PATCH] Match-id-97a6395f2682889472335c90b2a743d288f37fcc --- libs/horizon/src/renderer/ErrorHandler.ts | 4 +- libs/horizon/src/renderer/TreeBuilder.ts | 6 +- .../src/renderer/render/ClassComponent.ts | 8 +- .../src/renderer/submit/LifeCycleHandler.ts | 8 +- libs/horizon/src/renderer/submit/Submit.ts | 33 +++---- libs/horizon/src/renderer/vnode/VNode.ts | 18 +--- libs/horizon/src/renderer/vnode/VNodeFlags.ts | 90 ++++++++----------- libs/horizon/src/renderer/vnode/VNodeUtils.ts | 6 +- 8 files changed, 73 insertions(+), 100 deletions(-) diff --git a/libs/horizon/src/renderer/ErrorHandler.ts b/libs/horizon/src/renderer/ErrorHandler.ts index 991ef861..837f25c5 100644 --- a/libs/horizon/src/renderer/ErrorHandler.ts +++ b/libs/horizon/src/renderer/ErrorHandler.ts @@ -6,7 +6,7 @@ import type {VNode} from './Types'; import type {Update} from './UpdateHandler'; import {ClassComponent, TreeRoot} from './vnode/VNodeTags'; -import {FlagUtils, Interrupted} from './vnode/VNodeFlags'; +import {FlagUtils, Interrupted, DidCapture, InitFlag} from './vnode/VNodeFlags'; import {newUpdate, UpdateState, pushUpdate} from './UpdateHandler'; import {launchUpdateFromVNode, tryRenderFromRoot} from './TreeBuilder'; import {setRootThrowError} from './submit/Submit'; @@ -99,7 +99,7 @@ export function handleRenderThrowError( const ctor = vNode.type; const instance = vNode.realNode; if ( - !vNode.flags.DidCapture && + (vNode.flags & DidCapture) === InitFlag && ( typeof ctor.getDerivedStateFromError === 'function' || (instance !== null && typeof instance.componentDidCatch === 'function') diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts index d6f852b4..0f13627d 100644 --- a/libs/horizon/src/renderer/TreeBuilder.ts +++ b/libs/horizon/src/renderer/TreeBuilder.ts @@ -3,7 +3,7 @@ import type { VNode } from './Types'; import { callRenderQueueImmediate, pushRenderCallback } from './taskExecutor/RenderQueue'; import { updateVNode } from './vnode/VNodeCreator'; import { TreeRoot } from './vnode/VNodeTags'; -import { FlagUtils } from './vnode/VNodeFlags'; +import { FlagUtils, InitFlag, Interrupted } from './vnode/VNodeFlags'; import { captureVNode } from './render/BaseComponent'; import { checkLoopingUpdateLimit, submitToRender } from './submit/Submit'; import { runAsyncEffects } from './submit/HookEffectHandler'; @@ -86,13 +86,13 @@ function bubbleVNode(vNode: VNode): void { do { const parent = node.parent; - if (!node.flags.Interrupted) { // vNode没有抛出异常 + if ((node.flags & Interrupted) === InitFlag) { // vNode没有抛出异常 componentRenders[node.tag].bubbleRender(node); // 设置node的childShouldUpdate属性 updateChildShouldUpdate(node); - if (parent !== null && node !== getStartVNode() && !parent.flags.Interrupted) { + if (parent !== null && node !== getStartVNode() && (parent.flags & Interrupted) === InitFlag) { collectDirtyNodes(node, parent); } } diff --git a/libs/horizon/src/renderer/render/ClassComponent.ts b/libs/horizon/src/renderer/render/ClassComponent.ts index b459215c..9c4c1f20 100644 --- a/libs/horizon/src/renderer/render/ClassComponent.ts +++ b/libs/horizon/src/renderer/render/ClassComponent.ts @@ -20,7 +20,7 @@ import { markComponentDidUpdate, markGetSnapshotBeforeUpdate, } from './class/ClassLifeCycleProcessor'; -import { FlagUtils } from '../vnode/VNodeFlags'; +import { FlagUtils, DidCapture } from '../vnode/VNodeFlags'; import { createVNodeChildren, markRef } from './BaseComponent'; import { createUpdateArray, @@ -73,7 +73,7 @@ function createChildren(clazz: any, processing: VNode) { processing.state = processing.realNode.state; const inst = processing.realNode; - const isCatchError = processing.flags.DidCapture; + const isCatchError = (processing.flags & DidCapture) === DidCapture; // 按照已有规格,如果捕获了错误却没有定义getDerivedStateFromError函数,返回的child为null const newElements = isCatchError && typeof clazz.getDerivedStateFromError !== 'function' @@ -122,7 +122,7 @@ export function captureClassComponent(processing: VNode, clazz: any, nextProps: const newContext = getCurrentContext(clazz, processing); // 子节点抛出异常时,如果本class是个捕获异常的处理节点,这时候oldProps是null,所以需要使用props - let oldProps = processing.flags.DidCapture ? processing.props : processing.oldProps; + let oldProps = (processing.flags & DidCapture) === DidCapture ? processing.props : processing.oldProps; if (processing.isLazyComponent) { oldProps = mergeDefaultProps(processing.type, oldProps); } @@ -161,7 +161,7 @@ export function captureClassComponent(processing: VNode, clazz: any, nextProps: inst.props = nextProps; } // 如果捕获了 error,必须更新 - const isCatchError = processing.flags.DidCapture; + const isCatchError = (processing.flags & DidCapture) === DidCapture; shouldUpdate = isCatchError || shouldUpdate; // 更新ref diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index 354a179e..55edf2c7 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -17,7 +17,7 @@ import { SuspenseComponent, MemoComponent, } from '../vnode/VNodeTags'; -import { FlagUtils, ResetText, Clear } from '../vnode/VNodeFlags'; +import { FlagUtils, ResetText, Clear, Update } from '../vnode/VNodeFlags'; import { mergeDefaultProps } from '../render/LazyComponent'; import { submitDomUpdate, @@ -97,7 +97,7 @@ function callAfterSubmitLifeCycles( } case ClassComponent: { const instance = vNode.realNode; - if (vNode.flags.Update) { + if ((vNode.flags & Update) === Update) { if (vNode.isCreated) { instance.componentDidMount(); } else { @@ -124,7 +124,7 @@ function callAfterSubmitLifeCycles( return; } case DomComponent: { - if (vNode.isCreated && vNode.flags.Update) { + if (vNode.isCreated && (vNode.flags & Update) === Update) { // button、input、select、textarea、如果有 autoFocus 属性需要focus if (shouldAutoFocus(vNode.type, vNode.props)) { vNode.realNode.focus(); @@ -222,7 +222,7 @@ function unmountNestedVNodes(vNode: VNode): void { function submitAddition(vNode: VNode): void { const { parent, parentDom } = findDomParent(vNode); - if (parent.flags.ResetText) { + if ((vNode.flags & ResetText) === ResetText) { // 在insert之前先reset clearText(parentDom); FlagUtils.removeFlag(parent, ResetText); diff --git a/libs/horizon/src/renderer/submit/Submit.ts b/libs/horizon/src/renderer/submit/Submit.ts index 30fee9d8..ae4027f3 100644 --- a/libs/horizon/src/renderer/submit/Submit.ts +++ b/libs/horizon/src/renderer/submit/Submit.ts @@ -1,8 +1,6 @@ import type {VNode} from '../Types'; -import {callRenderQueueImmediate} from '../taskExecutor/RenderQueue'; -import {throwIfTrue} from '../utils/throwIfTrue'; -import {FlagUtils, Addition as AdditionFlag} from '../vnode/VNodeFlags'; +import {FlagUtils, Addition, Snapshot, ResetText, Ref, Update, Deletion, Clear, Callback} from '../vnode/VNodeFlags'; import {prepareForSubmit, resetAfterSubmit} from '../../dom/DOMOperator'; import {handleSubmitError} from '../ErrorHandler'; import { @@ -91,7 +89,7 @@ export function submitToRender(treeRoot) { function beforeSubmit(dirtyNodes: Array) { dirtyNodes.forEach(node => { try { - if (node.flags.Snapshot) { + if ((node.flags & Snapshot) === Snapshot) { callBeforeSubmitLifeCycles(node); } } catch (error) { @@ -103,35 +101,38 @@ function beforeSubmit(dirtyNodes: Array) { function submit(dirtyNodes: Array) { dirtyNodes.forEach(node => { try { - if (node.flags.ResetText) { + if ((node.flags & ResetText) === ResetText) { submitResetTextContent(node); } - if (node.flags.Ref) { + if ((node.flags & Ref) === Ref) { if (!node.isCreated) { // 需要执行 detachRef(node, true); } } - const {Addition, Update, Deletion, Clear} = node.flags; - if (Addition && Update) { + const isAdd = (node.flags & Addition) === Addition; + const isUpdate = (node.flags & Update) === Update; + if (isAdd && isUpdate) { // Addition submitAddition(node); - FlagUtils.removeFlag(node, AdditionFlag); + FlagUtils.removeFlag(node, Addition); // Update submitUpdate(node); } else { - if (Addition) { + const isDeletion = (node.flags & Deletion) === Deletion; + const isClear = (node.flags & Clear) === Clear; + if (isAdd) { submitAddition(node); - FlagUtils.removeFlag(node, AdditionFlag); - } else if (Update) { + FlagUtils.removeFlag(node, Addition); + } else if (isUpdate) { submitUpdate(node); - } else if (Deletion) { + } else if (isDeletion) { submitDeletion(node); } - if (Clear) { + if (isClear) { submitClear(node); } } @@ -144,11 +145,11 @@ function submit(dirtyNodes: Array) { function afterSubmit(dirtyNodes: Array) { dirtyNodes.forEach(node => { try { - if (node.flags.Update || node.flags.Callback) { + if ((node.flags & Update) === Update || (node.flags & Callback) === Callback) { callAfterSubmitLifeCycles(node); } - if (node.flags.Ref) { + if ((node.flags & Ref) === Ref) { attachRef(node); } } catch (error) { diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 9f9a66c0..5799e34c 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -5,6 +5,7 @@ import { TreeRoot, FunctionComponent, ClassComponent, DomPortal, DomText, Contex import type { VNodeTag } from './VNodeTags'; import type { RefType, ContextType } from '../Types'; import type { Hook } from '../hooks/HookType'; +import { InitFlag } from './VNodeFlags'; export class VNode { tag: VNodeTag; @@ -48,20 +49,7 @@ export class VNode { // 因为LazyComponent会修改type属性,为了在diff中判断是否可以复用,需要增加一个lazyType lazyType: any; - flags: { - Addition?: boolean; - Update?: boolean; - Deletion?: boolean; - ResetText?: boolean; - Callback?: boolean; - DidCapture?: boolean; - Ref?: boolean; - Snapshot?: boolean; - Interrupted?: boolean; - ShouldCapture?: boolean; - ForceUpdate?: boolean; - Clear?: boolean; - } = {}; + flags = InitFlag; clearChild: VNode | null; // one tree相关属性 isCreated: boolean = true; @@ -75,7 +63,7 @@ export class VNode { promiseResolve: boolean; // suspense的promise是否resolve path: string = ''; // 保存从根到本节点的路径 - toUpdateNodes: Set; // 保存要更新的节点 + toUpdateNodes: Set | null; // 保存要更新的节点 belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用 diff --git a/libs/horizon/src/renderer/vnode/VNodeFlags.ts b/libs/horizon/src/renderer/vnode/VNodeFlags.ts index 48d0331d..62f98803 100644 --- a/libs/horizon/src/renderer/vnode/VNodeFlags.ts +++ b/libs/horizon/src/renderer/vnode/VNodeFlags.ts @@ -4,97 +4,79 @@ import type { VNode } from '../Types'; + +export const InitFlag = /** */ 0b000000000000; // vNode节点的flags -export const Addition = 'Addition'; -export const Update = 'Update'; -export const Deletion = 'Deletion'; -export const ResetText = 'ResetText'; -export const Callback = 'Callback'; -export const DidCapture = 'DidCapture'; -export const Ref = 'Ref'; -export const Snapshot = 'Snapshot'; -// 被中断了,抛出错误的vNode以及它的父vNode -export const Interrupted = 'Interrupted'; -export const ShouldCapture = 'ShouldCapture'; -// For suspense -export const ForceUpdate = 'ForceUpdate'; -export const Clear = 'Clear'; - -const FlagArr = [Addition, Update, Deletion, Clear, ResetText, Callback, - DidCapture, Ref, Snapshot, Interrupted, ShouldCapture, ForceUpdate]; - -const LifecycleEffectArr = [Update, Callback, Ref, Snapshot]; - -function resetFlag(node) { - node.flags = {}; -} +export const Addition = /** */ 0b100000000000; +export const Update = /** */ 0b010000000000; +export const Deletion = /** */ 0b001000000000; +export const ResetText =/** */ 0b000100000000; +export const Callback = /** */ 0b000010000000; +export const DidCapture =/** */ 0b000001000000; +export const Ref = /** */ 0b000000100000; +export const Snapshot = /** */ 0b000000010000; +export const Interrupted = /** */ 0b000000001000; // 被中断了,抛出错误的vNode以及它的父vNode +export const ShouldCapture =/** */ 0b000000000100; +export const ForceUpdate = /** */ 0b000000000010; // For suspense +export const Clear = /** */ 0b000000000001; +const LifecycleEffectArr = Update | Callback | Ref | Snapshot; export class FlagUtils { - static removeFlag(node: VNode, flag: string) { - node.flags[flag] = false; + static removeFlag(node: VNode, flag: number) { + const flags = node.flags; + node.flags = flags & (~flag); } static removeLifecycleEffectFlags(node) { - LifecycleEffectArr.forEach(key => { - node.flags[key] = false; - }); + const flags = node.flags; + node.flags = flags & (~LifecycleEffectArr); } static hasAnyFlag(node: VNode) { // 有标志位 - const flags = node.flags; - const arrLength = FlagArr.length; - let key; - for (let i = 0; i < arrLength; i++) { - key = FlagArr[i]; - if (flags[key]) { - return true; - } - } - return false; + return node.flags !== InitFlag; } static setNoFlags(node: VNode) { - resetFlag(node); + node.flags = InitFlag; } static markAddition(node: VNode) { - node.flags.Addition = true; + node.flags |= Addition; } static setAddition(node: VNode) { - resetFlag(node); - node.flags.Addition = true; + node.flags = Addition; } static markUpdate(node: VNode) { - node.flags.Update = true; + node.flags |= Update; } static setDeletion(node: VNode) { - resetFlag(node); - node.flags.Deletion = true; + node.flags = Deletion; } static markContentReset(node: VNode) { - node.flags.ResetText = true; + node.flags |= ResetText; } static markCallback(node: VNode) { - node.flags.Callback = true; + node.flags |= Callback; } static markDidCapture(node: VNode) { - node.flags.DidCapture = true; + node.flags |= DidCapture; } static markShouldCapture(node: VNode) { - node.flags.ShouldCapture = true; + node.flags |= ShouldCapture; } static markRef(node: VNode) { - node.flags.Ref = true; + node.flags |= Ref; } static markSnapshot(node: VNode) { - node.flags.Snapshot = true; + node.flags |= Snapshot; } static markInterrupted(node: VNode) { - node.flags.Interrupted = true; + node.flags |= Interrupted; } static markForceUpdate(node: VNode) { - node.flags.ForceUpdate = true; + node.flags |= ForceUpdate; } + static markClear(node: VNode) { - node.flags.Clear = true; + node.flags |= Clear; } } diff --git a/libs/horizon/src/renderer/vnode/VNodeUtils.ts b/libs/horizon/src/renderer/vnode/VNodeUtils.ts index 78f18a50..c9d4b572 100644 --- a/libs/horizon/src/renderer/vnode/VNodeUtils.ts +++ b/libs/horizon/src/renderer/vnode/VNodeUtils.ts @@ -7,6 +7,7 @@ import type {VNode} from '../Types'; import {DomComponent, DomPortal, DomText, TreeRoot} from './VNodeTags'; import {isComment} from '../../dom/utils/Common'; import {getNearestVNode} from '../../dom/DOMInternalKeys'; +import { Addition, InitFlag } from './VNodeFlags'; export function travelChildren(beginVNode: VNode, handleVNode: Function, isFinish?: Function) { let node: VNode | null = beginVNode; @@ -92,6 +93,7 @@ export function clearVNode(vNode: VNode) { vNode.oldState = null; vNode.oldRef = null; vNode.oldChild = null; + vNode.flags = InitFlag; vNode.toUpdateNodes = null; @@ -186,7 +188,7 @@ export function getSiblingDom(vNode: VNode): Element | null { // 如果不是dom节点,往下找 while (!isDomVNode(node)) { // 如果节点也是Addition - if (node.flags.Addition) { + if ((node.flags & Addition) ===Addition) { continue findSibling; } @@ -200,7 +202,7 @@ export function getSiblingDom(vNode: VNode): Element | null { } } - if (!node.flags.Addition) { + if ((node.flags & Addition) ===InitFlag) { // 找到 return node.realNode; }