loading...

Handling large DOM with Angular

danielsc profile image Daniel Schreiber ・2 min read

Have you noticed that creating (i.e. instanciating) 1000 components is not instant in Anguar?

It kind of suprised me that this takes ~300ms on Chrome on my rather decent laptop. Depending on worse hardware and/or more complex components, this number might be larger and is well above the "instant" threshold of 200ms (see e.g. here).

It is known that a bloated DOM makes any web app sluggish - no difference for Angular. But you reach 1000 components rather fast, e.g. with a table with 30 rows and 30 components in each row. I know 30 components per row is not really small, but when nesting some stuff for reusability, this is reached easily.

To reproduce this without a complex app, I created https://daniel-sc.github.io/smartlook-performance-showcase/ (just ignore the stuff about smartlook).

This still leaves me kind of puzzled, any ideas what might be the cause or meaningful optimization? Please comment!!

Defer initialization

One possible workaround, is to defer the initialization of each row. This does not block the UI and the parent component could be rendered immediately, but comes at the cost of a higher total CPU usage, as all rows are added sepaerately to the DOM, hence the browser must run the layouting for each row instead of only once.

@Directive({
  selector: '[appDeferInit]'
})
export class DeferInitDirective implements OnInit {

  constructor(private templateRef: TemplateRef<any>,
              private viewContainer: ViewContainerRef) {
  }

  ngOnInit(): void {
    setTimeout(() => {
      this.viewContainer.createEmbeddedView(this.templateRef).markForCheck();
    });
  }
}

Usage:

<div class="row" *ngFor="let r of rows">
   <app-my-row-component *appDeferInit></app-my-row-component>
</div>

Discussion

markdown guide
 

I would check if there is any empty lifecycle hook in reusable components as they are triggered anyway and can slow down your application. I would also look at implementation details to see if there is some way to optimize it

 

Yeah - I had the same idea. But after timing ngOnInit etc I came to the conclusion that this would only yield small improvements but not orders of magnitude.