Skip to content

Commit 34a0ad7

Browse files
committed
wip(vapor): optimize v-for getItem
1 parent c89e01e commit 34a0ad7

File tree

1 file changed

+49
-31
lines changed

1 file changed

+49
-31
lines changed

packages/runtime-vapor/src/apiCreateFor.ts

+49-31
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { EffectScope, type ShallowRef, shallowRef } from '@vue/reactivity'
1+
import {
2+
EffectScope,
3+
type ShallowRef,
4+
isReactive,
5+
isShallow,
6+
shallowReadArray,
7+
shallowRef,
8+
toReactive,
9+
} from '@vue/reactivity'
210
import { getSequence, isArray, isObject, isString } from '@vue/shared'
311
import { createComment, createTextNode } from './dom/node'
412
import { type Block, Fragment, insert, remove as removeBlock } from './block'
@@ -33,6 +41,12 @@ class ForBlock extends Fragment {
3341

3442
type Source = any[] | Record<any, any> | number | Set<any> | Map<any, any>
3543

44+
type ResolvedSource = {
45+
values: any[]
46+
needsWrap: boolean
47+
keys?: string[]
48+
}
49+
3650
/*! #__NO_SIDE_EFFECTS__ */
3751
export const createFor = (
3852
src: () => Source,
@@ -59,8 +73,8 @@ export const createFor = (
5973
}
6074

6175
const renderList = () => {
62-
const source = src()
63-
const newLength = getLength(source)
76+
const source = normalizeSource(src())
77+
const newLength = source.values.length
6478
const oldLength = oldBlocks.length
6579
newBlocks = new Array(newLength)
6680

@@ -85,8 +99,7 @@ export const createFor = (
8599
// unkeyed fast path
86100
const commonLength = Math.min(newLength, oldLength)
87101
for (let i = 0; i < commonLength; i++) {
88-
const [item] = getItem(source, i)
89-
update((newBlocks[i] = oldBlocks[i]), item)
102+
update((newBlocks[i] = oldBlocks[i]), getItem(source, i)[0])
90103
}
91104
for (let i = oldLength; i < newLength; i++) {
92105
mount(source, i)
@@ -249,7 +262,7 @@ export const createFor = (
249262
}
250263

251264
const mount = (
252-
source: any,
265+
source: ResolvedSource,
253266
idx: number,
254267
anchor: Node | undefined = parentAnchor,
255268
): ForBlock => {
@@ -319,54 +332,59 @@ export const createFor = (
319332
}
320333

321334
export function createForSlots(
322-
source: Source,
335+
rawSource: Source,
323336
getSlot: (item: any, key: any, index?: number) => DynamicSlot,
324337
): DynamicSlot[] {
325-
const sourceLength = getLength(source)
338+
const source = normalizeSource(rawSource)
339+
const sourceLength = source.values.length
326340
const slots = new Array<DynamicSlot>(sourceLength)
327341
for (let i = 0; i < sourceLength; i++) {
328-
const [item, key, index] = getItem(source, i)
329-
slots[i] = getSlot(item, key, index)
342+
slots[i] = getSlot(...getItem(source, i))
330343
}
331344
return slots
332345
}
333346

334-
function getLength(source: any): number {
335-
if (isArray(source) || isString(source)) {
336-
return source.length
347+
function normalizeSource(source: any): ResolvedSource {
348+
let values = source
349+
let needsWrap = false
350+
let keys
351+
if (isArray(source)) {
352+
if (isReactive(source)) {
353+
needsWrap = !isShallow(source)
354+
values = shallowReadArray(source)
355+
}
356+
} else if (isString(source)) {
357+
values = source.split('')
337358
} else if (typeof source === 'number') {
338359
if (__DEV__ && !Number.isInteger(source)) {
339360
warn(`The v-for range expect an integer value but got ${source}.`)
340361
}
341-
return source
362+
values = new Array(source)
363+
for (let i = 0; i < source; i++) values[i] = i + 1
342364
} else if (isObject(source)) {
343365
if (source[Symbol.iterator as any]) {
344-
return Array.from(source as Iterable<any>).length
366+
values = Array.from(source as Iterable<any>)
345367
} else {
346-
return Object.keys(source).length
368+
keys = Object.keys(source)
369+
values = new Array(keys.length)
370+
for (let i = 0, l = keys.length; i < l; i++) {
371+
values[i] = source[keys[i]]
372+
}
347373
}
348374
}
349-
return 0
375+
return { values, needsWrap, keys }
350376
}
351377

352378
function getItem(
353-
source: any,
379+
{ keys, values, needsWrap }: ResolvedSource,
354380
idx: number,
355381
): [item: any, key: any, index?: number] {
356-
if (isArray(source) || isString(source)) {
357-
return [source[idx], idx, undefined]
358-
} else if (typeof source === 'number') {
359-
return [idx + 1, idx, undefined]
360-
} else if (isObject(source)) {
361-
if (source[Symbol.iterator as any]) {
362-
source = Array.from(source as Iterable<any>)
363-
return [source[idx], idx, undefined]
364-
} else {
365-
const key = Object.keys(source)[idx]
366-
return [source[key], key, idx]
367-
}
382+
const value = needsWrap ? toReactive(values[idx]) : values[idx]
383+
if (keys) {
384+
return [value, keys[idx], idx]
385+
} else {
386+
return [value, idx, undefined]
368387
}
369-
return null!
370388
}
371389

372390
function normalizeAnchor(node: Block): Node {

0 commit comments

Comments
 (0)