8000 refactor(watch deep): use bfs instead of dfs · vuejs/core@f68d595 · GitHub
[go: up one dir, main page]

Skip to content

Commit f68d595

Browse files
committed
refactor(watch deep): use bfs instead of dfs
1 parent 263f63f commit f68d595

File tree

1 file changed

+48
-20
lines changed

1 file changed

+48
-20
lines changed

packages/reactivity/src/watch.ts

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -333,35 +333,63 @@ expo 10000 rt function traverse(
333333
depth: number = Infinity,
334334
seen?: Set<unknown>,
335335
): unknown {
336+
const activeSeen = seen || new Set()
337+
const queue: Array<[any, number]> = []
336338
if (depth <= 0 || !isObject(value) || (value as any)[ReactiveFlags.SKIP]) {
337339
return value
338340
}
339-
340-
seen = seen || new Set()
341-
if (seen.has(value)) {
341+
if (activeSeen.has(value)) {
342342
return value
343343
}
344-
seen.add(value)
345-
depth--
346-
if (isRef(value)) {
347-
traverse(value.value, depth, seen)
348-
} else if (isArray(value)) {
349-
for (let i = 0; i < value.length; i++) {
350-
traverse(value[i], depth, seen)
344+
queue.push([value, depth])
345+
346+
while (queue.length > 0) {
347+
const [currentValue, currentDepth] = queue.shift()!
348+
349+
// 1. Check if 'currentValue' itself should be skipped based on its depth or type.
350+
// If currentDepth is <= 0, 'currentValue' is not added to 'activeSeen' by this path,
351+
// and its children are not explored.
352+
if (
353+
currentDepth <= 0 ||
354+
!isObject(currentValue) ||
355+
(currentValue as any)[ReactiveFlags.SKIP]
356+
) {
357+
continue
351358
}
352-
} else if (isSet(value) || isMap(value)) {
353-
value.forEach((v: any) => {
354-
traverse(v, depth, seen)
355-
})
356-
} else if (isPlainObject(value)) {
357-
for (const key in value) {
358-
traverse(value[key], depth, seen)
359+
360+
// 2. Check if 'currentValue' has already been seen.
361+
if (activeSeen.has(currentValue)) {
362+
continue
359363
}
360-
for (const key of Object.getOwnPropertySymbols(value)) {
361-
if (Object.prototype.propertyIsEnumerable.call(value, key)) {
362-
traverse(value[key as any], depth, seen)
364+
365+
// 3. If 'currentValue' is traversable and not yet seen, mark it as seen.
366+
activeSeen.add(currentValue)
367+
368+
// 4. Prepare for children: calculate their depth.
369+
const childrenDepth = currentDepth - 1
370+
371+
// 5. Enqueue children for processing.
372+
if (isRef(currentValue)) {
373+
queue.push([currentValue.value, childrenDepth])
374+
} else if (isArray(currentValue)) {
375+
for (let i = 0; i < currentValue.length; i++) {
376+
queue.push([currentValue[i], childrenDepth])
377+
}
378+
} else if (isSet(currentValue) || isMap(currentValue)) {
379+
currentValue.forEach((v: any) => {
380+
queue.push([v, childrenDepth])
381+
})
382+
} else if (isPlainObject(currentValue)) {
383+
for (const key in currentValue) {
384+
queue.push([currentValue[key], childrenDepth])
385+
}
386+
for (const key of Object.getOwnPropertySymbols(currentValue)) {
387+
if (Object.prototype.propertyIsEnumerable.call(currentValue, key)) {
388+
queue.push([currentValue[key as any], childrenDepth])
389+
}
363390
}
364391
}
365392
}
393+
366394
return value
367395
}

0 commit comments

Comments
 (0)
0