Skip to content

Conversation

@MayaKirova
Copy link
Contributor

@MayaKirova MayaKirova commented Jan 26, 2026

Closes #16821

Attach observer to individual root node views so that they track any change individually for that view. Update size accordingly.
Cache sizes of embedded views and use the cache when updating virtualization caches on scroll.

Additional information (check all that apply):

  • Bug fix
  • New functionality
  • Documentation
  • Demos
  • CI/CD

Checklist:

  • All relevant tags have been applied to this PR
  • This PR includes unit tests covering all the new code (test guidelines)
  • This PR includes API docs for newly added methods/properties (api docs guidelines)
  • This PR includes feature/README.MD updates for the feature docs
  • This PR includes general feature table updates in the root README.MD
  • This PR includes CHANGELOG.MD updates for newly added functionality
  • This PR contains breaking changes
  • This PR includes ng update migrations for the breaking changes (migrations guidelines)
  • This PR includes behavioral changes and the feature specification has been updated with them

@MayaKirova MayaKirova added squash-merge Merge PR with "Squash and Merge" option version: 21.1.x labels Feb 2, 2026
@MayaKirova MayaKirova marked this pull request as ready for review February 2, 2026 09:16
@MayaKirova MayaKirova added the ❌ status: awaiting-test PRs awaiting manual verification label Feb 2, 2026
@MayaKirova MayaKirova changed the title [POC] Refactor virtualization resize observer to track individual forOf elements. Refactor virtualization resize observer to track individual forOf elements. Feb 2, 2026
Copy link
Member

@rkaraivanov rkaraivanov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
I think we can squeeze out a little bit more perf with several of the points in this review.

protected platformUtil = inject(PlatformUtil);
protected document = inject(DOCUMENT);
private _igxForOf: U & T[] | null = null;
protected _embeddedViewSizesCache = new Map<EmbeddedViewRef<any>, number>();
Copy link
Member

@rkaraivanov rkaraivanov Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
protected _embeddedViewSizesCache = new Map<EmbeddedViewRef<any>, number>();
protected _embeddedViewSizesCache = new WeakMap<EmbeddedViewRef<any>, number>();

I don't see the viewSizesCache being iterated, so let's go with the more memory-friendly version.


for (let index = 0; index < this._embeddedViews.length; index++) {
const targetIndex = this.state.startIndex + index;
const nodeSize = this.getEmbeddedViewSize(index);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getEmbeddedViewSize calls get embeddedViewNodes which creates a new array and iterates all views on each access to the getter. This is O(n²) operations at least. I suggest to cache the embeddedViewNodes outside the loop and adjust the calculations based on that.

Comment on lines 883 to 888
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you drop the O(n) reduce operation?
Can you update the _virtSize with the totalDiff directly?
Something like:

this._virtSize += totalDiff;
if (this._virtSize > this._maxSize) {
    this._virtRatio = this._virtSize / this._maxSize;
}
this.scrollComponent.size = Math.min(this.scrollComponent.size + totalDiff, this._maxSize);
if (!this.scrollComponent.destroyed) {
    this.scrollComponent.cdr.detectChanges();
}


protected updateViewSizes(entries:ResizeObserverEntry[] ) {
entries.forEach((entry) => {
const index = parseInt(entry.target.getAttribute('data-index'), 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const index = parseInt(entry.target.getAttribute('data-index'), 0);
const index = parseInt(entry.target.getAttribute('data-index'), 10);

A typo

}

protected updateViewSizes(entries:ResizeObserverEntry[] ) {
entries.forEach((entry) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a simple for of loop instead of a forEach?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

grid: performance squash-merge Merge PR with "Squash and Merge" option version: 21.1.x ❌ status: awaiting-test PRs awaiting manual verification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Grid Virtualization - variable row height performance improvements

4 participants