Commit fe53279
Avoid sticky header scans for non-sticky VirtualizedLists (#57210)
Summary:
`VirtualizedList._createRenderMask` always did the sticky-header lookup, even when there were no sticky headers. For a large list scrolled far from the top, that meant walking backward from the first visible item toward index 0 on every render-mask update.
This changes that path to:
- skip the lookup when `stickyHeaderIndices` is missing or empty
- when sticky headers exist, scan the sticky header indices and pick the closest one above the viewport
- keep `ListHeaderComponent` offset handling and integer-index behavior
## Changelog:
[GENERAL][CHANGED] - Speed up VirtualizedList render-mask creation for large lists by avoiding the old backward sticky-header scan when sticky headers are missing or sparse.
## Affected components
This is inside `VirtualizedList`, so the affected callers are:
- `VirtualizedList`
- `FlatList`, because it renders through `VirtualizedList`
- `VirtualizedSectionList` / `SectionList`, because section lists also render through this path
`stickyHeaderIndices` does not need to be set to get the no-sticky win. A normal `FlatList` with no sticky headers still used to pay the backward scan. With this change, that case exits before the sticky-header helper runs.
When `stickyHeaderIndices` is set, the lookup changes from scanning item indices back toward 0 to scanning only the sticky header index array. The size of the win then depends on how many sticky headers are configured.
## Benchmark
Benchmark command:
```sh
yarn fantom --benchmarks packages/react-native/Libraries/Lists/__tests__/VirtualizedList-stickyHeaders-benchmark-itest.js --runInBand
```
Fantom Hermes benchmark, 100 samples per case. Values below are median latency for `VirtualizedList._createRenderMask` when the viewport is near the end of the list.
Per-call values are under 1 second, so they stay in milliseconds. For 1,000 render-mask updates, values over 1 second are shown in seconds.
| Case | One update before | One update after | Speedup | 1,000 updates before | 1,000 updates after |
| --- | ---: | ---: | ---: | ---: | ---: |
| 100k rows, no sticky headers | 2.664 ms | 0.0034 ms | 780x | 2.66 s | 3.42 ms |
| 100k rows, empty sticky headers | 2.632 ms | 0.0033 ms | 800x | 2.63 s | 3.29 ms |
| 100k rows, one top sticky header | 2.705 ms | 0.0054 ms | 499x | 2.71 s | 5.42 ms |
| 250k rows, no sticky headers | 6.543 ms | 0.0035 ms | 1,892x | 6.54 s | 3.46 ms |
| 250k rows, empty sticky headers | 6.579 ms | 0.0033 ms | 2,024x | 6.58 s | 3.25 ms |
| 250k rows, one top sticky header | 6.796 ms | 0.0053 ms | 1,294x | 6.80 s | 5.25 ms |
| 500k rows, no sticky headers | 13.173 ms | 0.0033 ms | 4,002x | 13.17 s | 3.29 ms |
| 500k rows, empty sticky headers | 13.073 ms | 0.0033 ms | 3,997x | 13.07 s | 3.27 ms |
| 500k rows, one top sticky header | 13.444 ms | 0.0054 ms | 2,511x | 13.44 s | 5.35 ms |
| 750k rows, no sticky headers | 19.524 ms | 0.0033 ms | 6,008x | 19.52 s | 3.25 ms |
| 750k rows, empty sticky headers | 19.572 ms | 0.0033 ms | 6,022x | 19.57 s | 3.25 ms |
| 750k rows, one top sticky header | 20.304 ms | 0.0054 ms | 3,778x | 20.30 s | 5.37 ms |
| 1m rows, no sticky headers | 26.190 ms | 0.0033 ms | 8,058x | 26.19 s | 3.25 ms |
| 1m rows, empty sticky headers | 26.039 ms | 0.0033 ms | 8,012x | 26.04 s | 3.25 ms |
| 1m rows, one top sticky header | 26.855 ms | 0.0053 ms | 5,075x | 26.86 s | 5.29 ms |
This benchmark is intentionally focused on this helper. It does not claim the whole app or whole list render becomes thousands of times faster. It shows that this hot helper is no longer proportional to the scroll distance from the top of the list.
Pull Request resolved: #57210
Test Plan:
```sh
yarn jest packages/virtualized-lists/Lists/__tests__/VirtualizedList-test.js packages/virtualized-lists/Lists/__tests__/VirtualizedSectionList-test.js packages/react-native/Libraries/Lists/__tests__/FlatList-test.js --runInBand
```
Passed: 3 suites, 101 tests, 1 skipped, 76 snapshots.
```sh
yarn fantom packages/react-native/Libraries/Lists/__tests__/FlatList-itest.js packages/react-native/Libraries/Lists/__tests__/SectionList-itest.js --runInBand
```
Passed: 2 suites, 64 tests.
```sh
yarn flow check
```
Passed: no errors.
```sh
./node_modules/.bin/eslint packages/virtualized-lists/Lists/VirtualizedList.js packages/virtualized-lists/Lists/__tests__/VirtualizedList-test.js packages/react-native/Libraries/Lists/__tests__/VirtualizedList-stickyHeaders-benchmark-itest.js
```
Passed.
```sh
git diff --check
```
Passed.
Reviewed By: javache
Differential Revision: D108890210
Pulled By: Abbondanzo
fbshipit-source-id: 7548ba29d77ac14a609665356ab7d09662820abe1 parent 9ab5dd8 commit fe53279
3 files changed
Lines changed: 178 additions & 13 deletions
File tree
- packages
- react-native/Libraries/Lists/__tests__
- virtualized-lists/Lists
- __tests__
Lines changed: 85 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
535 | 535 | | |
536 | 536 | | |
537 | 537 | | |
538 | | - | |
| 538 | + | |
539 | 539 | | |
540 | 540 | | |
541 | | - | |
542 | | - | |
543 | | - | |
544 | | - | |
545 | | - | |
546 | | - | |
547 | | - | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
548 | 550 | | |
549 | 551 | | |
550 | 552 | | |
| |||
575 | 577 | | |
576 | 578 | | |
577 | 579 | | |
578 | | - | |
| 580 | + | |
579 | 581 | | |
580 | 582 | | |
581 | 583 | | |
582 | 584 | | |
| 585 | + | |
| 586 | + | |
583 | 587 | | |
584 | | - | |
585 | | - | |
586 | | - | |
587 | | - | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
588 | 597 | | |
589 | 598 | | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
590 | 604 | | |
591 | 605 | | |
592 | 606 | | |
| |||
Lines changed: 66 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
988 | 988 | | |
989 | 989 | | |
990 | 990 | | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
| 1007 | + | |
| 1008 | + | |
| 1009 | + | |
| 1010 | + | |
| 1011 | + | |
| 1012 | + | |
| 1013 | + | |
| 1014 | + | |
| 1015 | + | |
| 1016 | + | |
| 1017 | + | |
| 1018 | + | |
| 1019 | + | |
| 1020 | + | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
| 1028 | + | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
991 | 1037 | | |
992 | 1038 | | |
993 | 1039 | | |
| |||
2569 | 2615 | | |
2570 | 2616 | | |
2571 | 2617 | | |
| 2618 | + | |
| 2619 | + | |
| 2620 | + | |
| 2621 | + | |
| 2622 | + | |
| 2623 | + | |
| 2624 | + | |
| 2625 | + | |
| 2626 | + | |
| 2627 | + | |
| 2628 | + | |
| 2629 | + | |
| 2630 | + | |
| 2631 | + | |
| 2632 | + | |
| 2633 | + | |
| 2634 | + | |
| 2635 | + | |
| 2636 | + | |
| 2637 | + | |
2572 | 2638 | | |
2573 | 2639 | | |
2574 | 2640 | | |
| |||
0 commit comments