Skip to content

Commit e7b41f2

Browse files
committed
perf(runtime-vapor): fast path to replace all rows
1 parent ca05635 commit e7b41f2

File tree

1 file changed

+77
-36
lines changed

1 file changed

+77
-36
lines changed

Diff for: packages/runtime-vapor/src/apiCreateFor.ts

+77-36
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ export const createFor = (
8585
const parentAnchor = __DEV__ ? createComment('for') : createTextNode()
8686
const frag = new VaporFragment(oldBlocks)
8787
const instance = currentInstance!
88-
const canUseFastRemove = flags & VaporVForFlags.FAST_REMOVE
89-
const isComponent = flags & VaporVForFlags.IS_COMPONENT
88+
const canUseFastRemove = !!(flags & VaporVForFlags.FAST_REMOVE)
89+
const isComponent = !!(flags & VaporVForFlags.IS_COMPONENT)
9090
const selectors: {
9191
deregister: (key: any) => void
9292
cleanup: () => void
@@ -196,28 +196,88 @@ export const createFor = (
196196
pendingNews.push([i, item, key])
197197
}
198198

199+
let pendingMountsLength = 0
200+
201+
const pendingMounts: [
202+
index: number,
203+
item: ReturnType<typeof getItem>,
204+
key: any,
205+
anchorIndex: number,
206+
][] = new Array(newLength)
207+
const moveOrMount = (
208+
index: number,
209+
item: ReturnType<typeof getItem>,
210+
key: any,
211+
anchorIndex: number,
212+
) => {
213+
const oldIndex = oldKeyToIndexMap.get(key)
214+
if (oldIndex !== undefined) {
215+
const block = (newBlocks[index] = oldBlocks[oldIndex])
216+
update(block, ...item)
217+
insert(
218+
block,
219+
parent!,
220+
anchorIndex === -1
221+
? defaultAnchor
222+
: normalizeAnchor(newBlocks[anchorIndex].nodes),
223+
)
224+
oldKeyToIndexMap.delete(key)
225+
} else {
226+
pendingMounts[pendingMountsLength++] = [
227+
index,
228+
item,
229+
key,
230+
anchorIndex,
231+
]
232+
}
233+
}
234+
199235
for (let i = pendingNews.length - 1; i >= 0; i--) {
200236
const [index, item, key] = pendingNews[i]
201237
moveOrMount(
202-
oldKeyToIndexMap,
203-
source,
204238
index,
205239
item,
206240
key,
207-
index < prepareLength - 1
208-
? normalizeAnchor(newBlocks[index + 1].nodes)
209-
: defaultAnchor,
241+
index < prepareLength - 1 ? index + 1 : -1,
210242
)
211243
}
212244

213245
for (let i = prepareLength; i < newLength - right; i++) {
214246
const item = getItem(source, i)
215247
const key = getKey.apply(null, item)
216-
moveOrMount(oldKeyToIndexMap, source, i, item, key, defaultAnchor)
248+
moveOrMount(i, item, key, -1)
217249
}
218250

251+
const shouldUseFastRemove = pendingMountsLength === newLength
252+
219253
for (const i of oldKeyToIndexMap.values()) {
220-
unmount(oldBlocks[i])
254+
unmount(
255+
oldBlocks[i],
256+
!(shouldUseFastRemove && canUseFastRemove),
257+
!shouldUseFastRemove,
258+
)
259+
}
260+
if (shouldUseFastRemove) {
261+
for (const selector of selectors) {
262+
selector.cleanup()
263+
}
264+
}
265+
if (shouldUseFastRemove && canUseFastRemove) {
266+
parent!.textContent = ''
267+
parent!.appendChild(parentAnchor)
268+
}
269+
270+
for (let i = 0; i < pendingMountsLength; i++) {
271+
const [index, item, key, anchorIndex] = pendingMounts[i]
272+
mount(
273+
source,
274+
index,
275+
item,
276+
key,
277+
anchorIndex === -1
278+
? defaultAnchor
279+
: normalizeAnchor(newBlocks[anchorIndex].nodes),
280+
)
221281
}
222282
}
223283
}
@@ -272,25 +332,6 @@ export const createFor = (
272332
return block
273333
}
274334

275-
const moveOrMount = (
276-
keyToOldIndexMap: Map<any, number>,
277-
source: ResolvedSource,
278-
index: number,
279-
item: ReturnType<typeof getItem>,
280-
key: any,
281-
anchor: Node,
282-
) => {
283-
const oldIndex = keyToOldIndexMap.get(key)
284-
if (oldIndex !== undefined) {
285-
const block = (newBlocks[index] = oldBlocks[oldIndex])
286-
update(block, ...item)
287-
insert(block, parent!, anchor)
288-
keyToOldIndexMap.delete(key)
289-
} else {
290-
mount(source, index, item, key, anchor)
291-
}
292-
}
293-
294335
const update = (
295336
{ itemRef, keyRef, indexRef }: ForBlock,
296337
newItem: any,
@@ -308,16 +349,16 @@ export const createFor = (
308349
}
309350
}
310351

311-
const unmount = (
312-
{ nodes, scope, key }: ForBlock,
313-
doRemove = true,
314-
doDeregister = true,
315-
) => {
316-
scope && scope.stop()
317-
doRemove && removeBlock(nodes, parent!)
352+
const unmount = (block: ForBlock, doRemove = true, doDeregister = true) => {
353+
if (!isComponent) {
354+
block.scope!.stop()
355+
}
356+
if (doRemove) {
357+
removeBlock(block.nodes, parent!)
358+
}
318359
if (doDeregister) {
319360
for (const selector of selectors) {
320-
selector.deregister(key)
361+
selector.deregister(block.key)
321362
}
322363
}
323364
}

0 commit comments

Comments
 (0)