Skip to content

Commit 63bd8d3

Browse files
committed
refactor: avoid allocating extra object when diffing v-for
1 parent 696c6d6 commit 63bd8d3

File tree

2 files changed

+25
-30
lines changed

2 files changed

+25
-30
lines changed

src/directives/for.ts

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/
99
const stripParensRE = /^\(|\)$/g
1010
const destructureRE = /^[{[]\s*((?:[\w_$]+\s*,?\s*)+)[\]}]$/
1111

12-
interface ChildScope {
13-
ctx: Context
14-
key: any
15-
}
16-
1712
type KeyToIndexMap = Map<any, number>
1813

1914
export const _for = (el: Element, exp: string, ctx: Context) => {
@@ -63,39 +58,37 @@ export const _for = (el: Element, exp: string, ctx: Context) => {
6358

6459
let mounted = false
6560
let blocks: Block[]
66-
let scopes: ChildScope[]
61+
let childCtxs: Context[]
6762
let keyToIndexMap: Map<any, number>
6863

69-
const createChildScopes = (
70-
source: unknown
71-
): [ChildScope[], KeyToIndexMap] => {
64+
const createChildContexts = (source: unknown): [Context[], KeyToIndexMap] => {
7265
const map: KeyToIndexMap = new Map()
73-
const scopes: ChildScope[] = []
66+
const ctxs: Context[] = []
7467

7568
if (isArray(source)) {
7669
for (let i = 0; i < source.length; i++) {
77-
scopes.push(createScope(map, source[i], i))
70+
ctxs.push(createChildContext(map, source[i], i))
7871
}
7972
} else if (typeof source === 'number') {
8073
for (let i = 0; i < source; i++) {
81-
scopes.push(createScope(map, i + 1, i))
74+
ctxs.push(createChildContext(map, i + 1, i))
8275
}
8376
} else if (isObject(source)) {
8477
let i = 0
8578
for (const key in source) {
86-
scopes.push(createScope(map, source[key], i++, key))
79+
ctxs.push(createChildContext(map, source[key], i++, key))
8780
}
8881
}
8982

90-
return [scopes, map]
83+
return [ctxs, map]
9184
}
9285

93-
const createScope = (
86+
const createChildContext = (
9487
map: KeyToIndexMap,
9588
value: any,
9689
index: number,
9790
objKey?: string
98-
): ChildScope => {
91+
): Context => {
9992
const data: any = {}
10093
if (destructureBindings) {
10194
destructureBindings.forEach(
@@ -113,25 +106,23 @@ export const _for = (el: Element, exp: string, ctx: Context) => {
113106
const childCtx = createScopedContext(ctx, data)
114107
const key = keyExp ? evaluate(childCtx.scope, keyExp) : index
115108
map.set(key, index)
116-
return {
117-
ctx: childCtx,
118-
key
119-
}
109+
childCtx.key = key
110+
return childCtx
120111
}
121112

122-
const mountBlock = ({ ctx, key }: ChildScope, ref: Node) => {
113+
const mountBlock = (ctx: Context, ref: Node) => {
123114
const block = new Block(el, ctx)
124-
block.key = key
115+
block.key = ctx.key
125116
block.insert(parent, ref)
126117
return block
127118
}
128119

129120
ctx.effect(() => {
130121
const source = evaluate(ctx.scope, sourceExp)
131122
const prevKeyToIndexMap = keyToIndexMap
132-
;[scopes, keyToIndexMap] = createChildScopes(source)
123+
;[childCtxs, keyToIndexMap] = createChildContexts(source)
133124
if (!mounted) {
134-
blocks = scopes.map((s) => mountBlock(s, anchor))
125+
blocks = childCtxs.map((s) => mountBlock(s, anchor))
135126
mounted = true
136127
} else {
137128
const nextBlocks: Block[] = []
@@ -141,21 +132,24 @@ export const _for = (el: Element, exp: string, ctx: Context) => {
141132
}
142133
}
143134

144-
let i = scopes.length
135+
let i = childCtxs.length
145136
while (i--) {
146-
const scope = scopes[i]
147-
const oldIndex = prevKeyToIndexMap.get(scope.key)
148-
const next = scopes[i + 1]
137+
const childCtx = childCtxs[i]
138+
const oldIndex = prevKeyToIndexMap.get(childCtx.key)
139+
const next = childCtxs[i + 1]
149140
const nextBlockOldIndex = next && prevKeyToIndexMap.get(next.key)
150141
const nextBlock =
151142
nextBlockOldIndex == null ? undefined : blocks[nextBlockOldIndex]
152143
if (oldIndex == null) {
153144
// new
154-
nextBlocks[i] = mountBlock(scope, nextBlock ? nextBlock.el : anchor)
145+
nextBlocks[i] = mountBlock(
146+
childCtx,
147+
nextBlock ? nextBlock.el : anchor
148+
)
155149
} else {
156150
// update
157151
const block = (nextBlocks[i] = blocks[oldIndex])
158-
Object.assign(block.ctx.scope, scope.ctx.scope)
152+
Object.assign(block.ctx.scope, childCtx.scope)
159153
if (oldIndex !== i) {
160154
// moved
161155
if (blocks[oldIndex + 1] !== nextBlock) {

src/walk.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { checkAttr } from './utils'
1313
import { ref } from './directives/ref'
1414

1515
export interface Context {
16+
key?: any
1617
scope: Record<string, any>
1718
dirs: Record<string, Directive>
1819
blocks: Block[]

0 commit comments

Comments
 (0)