From b7ca9e5d5ddb2ba4a92e51c1eee039622248461b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?= Date: Sat, 5 Oct 2024 21:23:37 +0800 Subject: [PATCH] feat(runtime-vapor): fast path for clear all children --- packages/compiler-vapor/src/generators/for.ts | 14 ++++++++- packages/compiler-vapor/src/ir/index.ts | 1 + .../compiler-vapor/src/transforms/vFor.ts | 10 +++++++ packages/runtime-vapor/src/apiCreateFor.ts | 30 ++++++++++++++----- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/packages/compiler-vapor/src/generators/for.ts b/packages/compiler-vapor/src/generators/for.ts index 21fb2ed02..ddfd61e1b 100644 --- a/packages/compiler-vapor/src/generators/for.ts +++ b/packages/compiler-vapor/src/generators/for.ts @@ -16,7 +16,18 @@ export function genFor( context: CodegenContext, ): CodeFragment[] { const { vaporHelper } = context - const { source, value, key, index, render, keyProp, once, id, memo } = oper + const { + source, + value, + key, + index, + render, + keyProp, + once, + id, + memo, + container, + } = oper let isDestructureAssignment = false let rawValue: string | null = null @@ -61,6 +72,7 @@ export function genFor( blockFn, genCallback(keyProp), genCallback(memo), + container != null && `n${container}`, false, // todo: hydrationNode once && 'true', ), diff --git a/packages/compiler-vapor/src/ir/index.ts b/packages/compiler-vapor/src/ir/index.ts index f4157a516..8e10ab0a7 100644 --- a/packages/compiler-vapor/src/ir/index.ts +++ b/packages/compiler-vapor/src/ir/index.ts @@ -86,6 +86,7 @@ export interface ForIRNode extends BaseIRNode, IRFor { keyProp?: SimpleExpressionNode render: BlockIRNode once: boolean + container?: number } export interface SetPropIRNode extends BaseIRNode { diff --git a/packages/compiler-vapor/src/transforms/vFor.ts b/packages/compiler-vapor/src/transforms/vFor.ts index a5ed245c2..735c086bf 100644 --- a/packages/compiler-vapor/src/transforms/vFor.ts +++ b/packages/compiler-vapor/src/transforms/vFor.ts @@ -56,6 +56,15 @@ export function processFor( return (): void => { exitBlock() + const { parent } = context + let container: number | undefined + if ( + parent && + parent.block.node !== parent.node && + parent.node.children.length === 1 + ) { + container = parent.reference() + } context.registerOperation({ type: IRNodeTypes.FOR, id, @@ -67,6 +76,7 @@ export function processFor( render, once: context.inVOnce, memo: memo && memo.exp, + container, }) } } diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 29913ac04..dabeb27e7 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -38,6 +38,7 @@ export const createFor = ( renderItem: (block: ForBlock['state']) => Block, getKey?: (item: any, key: any, index?: number) => any, getMemo?: (item: any, key: any, index?: number) => any[], + container?: ParentNode, hydrationNode?: Node, once?: boolean, ): Fragment => { @@ -45,7 +46,11 @@ export const createFor = ( let oldBlocks: ForBlock[] = [] let newBlocks: ForBlock[] let parent: ParentNode | undefined | null - const parentAnchor = __DEV__ ? createComment('for') : createTextNode() + const parentAnchor = container + ? undefined + : __DEV__ + ? createComment('for') + : createTextNode() const ref: Fragment = { nodes: oldBlocks, [fragmentKey]: true, @@ -71,14 +76,22 @@ export const createFor = ( isMounted = true mountList(source) } else { - parent = parent || parentAnchor.parentNode + parent = parent || container || parentAnchor!.parentNode if (!oldLength) { // fast path for all new mountList(source) } else if (!newLength) { - // fast path for clearing - for (let i = 0; i < oldLength; i++) { - unmount(oldBlocks[i]) + // fast path for all removed + if (container) { + container.textContent = '' + for (let i = 0; i < oldLength; i++) { + oldBlocks[i].scope.stop() + } + } else { + // fast path for clearing + for (let i = 0; i < oldLength; i++) { + unmount(oldBlocks[i]) + } } } else if (!getKey) { // unkeyed fast path @@ -239,13 +252,16 @@ export const createFor = ( } } - ref.nodes = [(oldBlocks = newBlocks), parentAnchor] + ref.nodes = [(oldBlocks = newBlocks)] + if (parentAnchor) { + ref.nodes.push(parentAnchor) + } } function mount( source: any, idx: number, - anchor: Node = parentAnchor, + anchor: Node | undefined = parentAnchor, ): ForBlock { const scope = effectScope()