Skip to content

Commit 7d61a38

Browse files
seob717claude
andcommitted
perf: optimize lane lookup from O(n) to O(1)
Use laneLastIndex array to track last item per lane instead of iterating through all measurements. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 8f360f5 commit 7d61a38

1 file changed

Lines changed: 17 additions & 16 deletions

File tree

packages/virtual-core/src/index.ts

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -614,20 +614,6 @@ export class Virtualizer<
614614
: undefined
615615
}
616616

617-
// Helper to find the last item in a specific lane before currentIndex
618-
private findLastItemInLane = (
619-
measurements: Array<VirtualItem>,
620-
currentIndex: number,
621-
lane: number,
622-
): VirtualItem | undefined => {
623-
for (let m = currentIndex - 1; m >= 0; m--) {
624-
if (measurements[m]?.lane === lane) {
625-
return measurements[m]
626-
}
627-
}
628-
return undefined
629-
}
630-
631617
private getMeasurementOptions = memo(
632618
() => [
633619
this.options.count,
@@ -717,6 +703,17 @@ export class Virtualizer<
717703

718704
const measurements = this.measurementsCache.slice(0, min)
719705

706+
// ✅ Performance: Track last item index per lane for O(1) lookup
707+
const laneLastIndex: Array<number | undefined> = new Array(lanes).fill(undefined)
708+
709+
// Initialize from existing measurements (before min)
710+
for (let m = 0; m < min; m++) {
711+
const item = measurements[m]
712+
if (item) {
713+
laneLastIndex[item.lane] = m
714+
}
715+
}
716+
720717
for (let i = min; i < count; i++) {
721718
const key = getItemKey(i)
722719

@@ -726,9 +723,10 @@ export class Virtualizer<
726723
let start: number
727724

728725
if (cachedLane !== undefined && this.options.lanes > 1) {
729-
// Use cached lane - find previous item in same lane for start position
726+
// Use cached lane - O(1) lookup for previous item in same lane
730727
lane = cachedLane
731-
const prevInLane = this.findLastItemInLane(measurements, i, lane)
728+
const prevIndex = laneLastIndex[lane]
729+
const prevInLane = prevIndex !== undefined ? measurements[prevIndex] : undefined
732730
start = prevInLane
733731
? prevInLane.end + this.options.gap
734732
: paddingStart + scrollMargin
@@ -769,6 +767,9 @@ export class Virtualizer<
769767
key,
770768
lane,
771769
}
770+
771+
// ✅ Performance: Update lane's last item index
772+
laneLastIndex[lane] = i
772773
}
773774

774775
this.measurementsCache = measurements

0 commit comments

Comments
 (0)