Skip to content

Commit bcb9209

Browse files
committed
wip(vapor): optimize unmounted children removal
1 parent 76e8d2c commit bcb9209

File tree

2 files changed

+59
-7
lines changed

2 files changed

+59
-7
lines changed

packages/runtime-vapor/src/block.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,19 @@ export function prepend(parent: ParentNode, ...blocks: Block[]): void {
126126
while (i--) insert(blocks[i], parent, 0)
127127
}
128128

129+
/**
130+
* Optimized children removal: record all parents with unmounted children
131+
* during each root remove call, and update their children list by filtering
132+
* unmounted children
133+
*/
134+
export let parentsWithUnmountedChildren: Set<VaporComponentInstance> | null =
135+
null
136+
129137
export function remove(block: Block, parent: ParentNode): void {
138+
const isRoot = !parentsWithUnmountedChildren
139+
if (isRoot) {
140+
parentsWithUnmountedChildren = new Set()
141+
}
130142
if (block instanceof Node) {
131143
parent.removeChild(block)
132144
} else if (isVaporComponent(block)) {
@@ -143,4 +155,10 @@ export function remove(block: Block, parent: ParentNode): void {
143155
;(block as DynamicFragment).scope!.stop()
144156
}
145157
}
158+
if (isRoot) {
159+
for (const i of parentsWithUnmountedChildren!) {
160+
i.children = i.children.filter(n => !n.isUnmounted)
161+
}
162+
parentsWithUnmountedChildren = null
163+
}
146164
}

packages/runtime-vapor/src/component.ts

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,28 @@ import {
2525
unregisterHMR,
2626
warn,
2727
} from '@vue/runtime-dom'
28-
import { type Block, insert, isBlock, remove } from './block'
28+
import {
29+
type Block,
30+
insert,
31+
isBlock,
32+
parentsWithUnmountedChildren,
33+
remove,
34+
} from './block'
2935
import {
3036
markRaw,
3137
pauseTracking,
3238
proxyRefs,
3339
resetTracking,
3440
unref,
3541
} from '@vue/reactivity'
36-
import { EMPTY_OBJ, invokeArrayFns, isFunction, isString } from '@vue/shared'
42+
import {
43+
EMPTY_ARR,
44+
EMPTY_OBJ,
45+
invokeArrayFns,
46+
isFunction,
47+
isString,
48+
remove as removeItem,
49+
} from '@vue/shared'
3750
import {
3851
type DynamicPropsSource,
3952
type RawProps,
@@ -465,24 +478,45 @@ export function mountComponent(
465478

466479
export function unmountComponent(
467480
instance: VaporComponentInstance,
468-
parent?: ParentNode,
481+
parentNode?: ParentNode,
469482
): void {
470483
if (instance.isMounted && !instance.isUnmounted) {
471484
if (__DEV__ && instance.type.__hmrId) {
472485
unregisterHMR(instance)
473486
}
474-
if (instance.bum) invokeArrayFns(instance.bum)
487+
if (instance.bum) {
488+
invokeArrayFns(instance.bum)
489+
}
490+
475491
instance.scope.stop()
492+
476493
for (const c of instance.children) {
477494
unmountComponent(c)
478495
}
479-
if (parent) remove(instance.block, parent)
496+
instance.children = EMPTY_ARR as any
497+
498+
if (parentNode) {
499+
// root remove: need to both remove this instance's DOM nodes
500+
// and also remove it from the parent's children list.
501+
remove(instance.block, parentNode)
502+
const parentInstance = instance.parent
503+
if (isVaporComponent(parentInstance)) {
504+
if (parentsWithUnmountedChildren) {
505+
// for optimize children removal
506+
parentsWithUnmountedChildren.add(parentInstance)
507+
} else {
508+
removeItem(parentInstance.children, instance)
509+
}
510+
instance.parent = null
511+
}
512+
}
513+
480514
if (instance.um) {
481515
queuePostFlushCb(() => invokeArrayFns(instance.um!))
482516
}
483517
instance.isUnmounted = true
484-
} else if (parent) {
485-
remove(instance.block, parent)
518+
} else if (parentNode) {
519+
remove(instance.block, parentNode)
486520
}
487521
}
488522

0 commit comments

Comments
 (0)