@@ -333,35 +333,63 @@ expo
10000
rt function traverse(
333
333
depth : number = Infinity ,
334
334
seen ?: Set < unknown > ,
335
335
) : unknown {
336
+ const activeSeen = seen || new Set ( )
337
+ const queue : Array < [ any , number ] > = [ ]
336
338
if ( depth <= 0 || ! isObject ( value ) || ( value as any ) [ ReactiveFlags . SKIP ] ) {
337
339
return value
338
340
}
339
-
340
- seen = seen || new Set ( )
341
- if ( seen . has ( value ) ) {
341
+ if ( activeSeen . has ( value ) ) {
342
342
return value
343
343
}
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
351
358
}
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
359
363
}
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
+ }
363
390
}
364
391
}
365
392
}
393
+
366
394
return value
367
395
}
0 commit comments