Performance enhancement strategies in Angular

Bulruno
2 min readMar 9, 2020

--

Replace

ChangeDetectorRef.detectChanges() with ChangeDetectorRef.markForCheck()

Reason: Synchronous blocks rendering violates parent -> child data flow. Can’t be batched

2. IterableDiffers

Unnecessary CPU/Memory Usage

Replace

[ngClass]=”’foo’” withclass=”foo”

Replace

[ngStyle]=”{color='red'}” with {style.color]="red"

Replace

*ngFor="let item of items" with *ngFor=(const item of items)

7

Replace

<div *ngFor="let item of items">
<ng-container *ngTemplateOutlet="itemTemplate"/>
<ng-template #itemTemplate">foo</ng-template>
</div>
with<div *ngFor="let item of items">
<ng-container *ngTemplateOutlet="itemTemplate"/>
</div>
<ng-template #itemTemplate">foo</ng-template>

Reason: Angular initializes ng-template per item and unnecessary CPU utilization.

8.

Replace

@Directive({ selector:'tooltip'}, host:{'mouseover':show()} })
export class Tooltip{}
with@Injectable({ provideIn:'root'} })
export class Tooltip{
constructor(){
document.addEventListener(mouseover)
}
}

9. Replace

@Directive({selector:’[cell]’})
export class DirecvPerCellInTable{
ngAfterViewInit() {
element.classList.add(‘foo’);
const foo = element.offsetHeight;
}
}
with

Fastdom.measure(()=>{foo=element.offsetHeight;})

Reason: Chrome has to recalculate the layout to come up with answer

Benchmarks showed 80% drop in renderTime

10. Replace

<table>
<tr *ngFor=”let item of items”>
<td>mat-checkbox></mat-checkbox></td>
</tr>
</table>
with<table>
<tr *ngFor=”let item of items”>
<td><mat-pseudo-checkbox></mat-pseudo-checkbox></td>
</tr>
</table>

Reason: Less Angular binding

Less DOM

Don’t forget to add back aria roles

DOM for mat-checkbox is heavy

Benchmarks showed 8% drop in renderTime

11. Replace

promise.resolve(foo)
setInterval(foo)
function foo() {el.classList.add(‘foo’); }withthis.ngZone.runOutsideAngular(()={setTimeout(foo);})

Reason: Angular wraps setTimeout, to execute change detection. You don’t need Angular CD

12. Replace

@Directive({selector:’[cell]’})
export class DirctvPerCellInTable{
ngAfterViewInit() {
setTimeout(()=>{…}
)
}
}
with @CompositionEvent({selector: ‘table’})
export class Table{
ngAfterViewInit() {
setTimeout(()=>{…}
)
}

Reason: After each setTimeout Angular executes changes detection.

Batching setTimeout has increased performance 56%

13. Replace

@Directive({selector:’tooltip’, host: {‘mousewheel’:’foo()’},})
export class ActiveListeners{foo(){…}}
with
@Directive({selector:’tooltip’})
export class ActiveListeners{constructor(){document.addEventListener(‘touchstart’,()={…}, {passive: true})}}

Reason: Chrome blocks rendering if the listener is not passive!

Angular doesn’t support this yet

14. Replace .show-on-hover{opacity: 0;}

.show-on-:hovered{opacity: 1;}

with .show-on-hover{opacity: 0;}

.show-on-:hovered{opacity: 1; will-change: opacity;}

Reason: Potential layout thrashing.

15. Replace

opacity: 0;with visibility: hidden;

Reason: Inefficient painting in Chrome

16. Replace letter-spacing: letter-spacing: 0;

with $non-zero-value

Reason: letter-spacing causes post processing in Chrome

Benchmarks have showed 15% improvement in renderTime.

--

--