-
-
Notifications
You must be signed in to change notification settings - Fork 8.7k
refactor(watch deep): use bfs instead of dfs #13433
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -333,35 +333,63 @@ export function traverse( | |
depth: number = Infinity, | ||
seen?: Set<unknown>, | ||
): unknown { | ||
const activeSeen = seen || new Set() | ||
const queue: Array<[any, number]> = [] | ||
Comment on lines
+336
to
+337
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't they be declared after the check line 338? Also it could be nice to directly add value and depth when declaring for performance Benchmark (~2.25x faster)There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes , you are right。 I will move these two lines to the bottom |
||
if (depth <= 0 || !isObject(value) || (value as any)[ReactiveFlags.SKIP]) { | ||
return value | ||
} | ||
|
||
seen = seen || new Set() | ||
if (seen.has(value)) { | ||
if (activeSeen.has(value)) { | ||
return value | ||
} | ||
seen.add(value) | ||
depth-- | ||
if (isRef(value)) { | ||
traverse(value.value, depth, seen) | ||
} else if (isArray(value)) { | ||
for (let i = 0; i < value.length; i++) { | ||
traverse(value[i], depth, seen) | ||
queue.push([value, depth]) | ||
|
||
while (queue.length > 0) { | ||
const [currentValue, currentDepth] = queue.shift()! | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The time complexity of const queue: Array<[any, number]> = []
let queueIndex = 0
const [currentValue, currentDepth] = queue[queueIndex++] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep,you are right! |
||
|
||
// 1. Check if 'currentValue' itself should be skipped based on its depth or type. | ||
// If currentDepth is <= 0, 'currentValue' is not added to 'activeSeen' by this path, | ||
// and its children are not explored. | ||
if ( | ||
currentDepth <= 0 || | ||
!isObject(currentValue) || | ||
(currentValue as any)[ReactiveFlags.SKIP] | ||
) { | ||
continue | ||
} | ||
} else if (isSet(value) || isMap(value)) { | ||
value.forEach((v: any) => { | ||
traverse(v, depth, seen) | ||
}) | ||
} else if (isPlainObject(value)) { | ||
for (const key in value) { | ||
traverse(value[key], depth, seen) | ||
|
||
// 2. Check if 'currentValue' has already been seen. | ||
if (activeSeen.has(currentValue)) { | ||
continue | ||
} | ||
for (const key of Object.getOwnPropertySymbols(value)) { | ||
if (Object.prototype.propertyIsEnumerable.call(value, key)) { | ||
traverse(value[key as any], depth, seen) | ||
|
||
// 3. If 'currentValue' is traversable and not yet seen, mark it as seen. | ||
activeSeen.add(currentValue) | ||
|
||
// 4. Prepare for children: calculate their depth. | ||
const childrenDepth = currentDepth - 1 | ||
|
||
// 5. Enqueue children for processing. | ||
if (isRef(currentValue)) { | ||
queue.push([currentValue.value, childrenDepth]) | ||
} else if (isArray(currentValue)) { | ||
for (let i = 0; i < currentValue.length; i++) { | ||
queue.push([currentValue[i], childrenDepth]) | ||
} | ||
} else if (isSet(currentValue) || isMap(currentValue)) { | ||
currentValue.forEach((v: any) => { | ||
queue.push([v, childrenDepth]) | ||
}) | ||
} else if (isPlainObject(currentValue)) { | ||
for (const key in currentValue) { | ||
queue.push([currentValue[key], childrenDepth]) | ||
} | ||
for (const key of Object.getOwnPropertySymbols(currentValue)) { | ||
if (Object.prototype.propertyIsEnumerable.call(currentValue, key)) { | ||
queue.push([currentValue[key as any], childrenDepth]) | ||
} | ||
} | ||
} | ||
} | ||
|
||
return value | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that
seen
is no longer needed here.