FusionReactor Observability & APM

Installation

Downloads

Quick Start for Java

Observability Agent

Ingesting Logs

System Requirements

Configure

On-Premise Quickstart

Cloud Quickstart

Application Naming

Tagging Metrics

Building Dashboards

Setting up Alerts

Troubleshoot

Performance Issues

Stability / Crashes

Low-level Debugging

Blog / Media

Blog

Videos / Webinars

Customers

Video Reviews

Reviews

Success Stories

About Us

Company

Careers

Contact

Contact support

Installation

Downloads

Quick Start for Java

Observability Agent

Ingesting Logs

System Requirements

Configure

On-Premise Quickstart

Cloud Quickstart

Application Naming

Tagging Metrics

Building Dashboards

Setting up Alerts

Troubleshoot

Performance Issues

Stability / Crashes

Debugging

Blog / Media

Blog

Videos / Webinars

Customers

Video Reviews

Reviews

Success Stories

About Us

Company

Careers

Contact

Contact support

How I improved Angular performance and page responsiveness

[vc_row][vc_column][vc_column_text]

How I improved Angular performance and page responsiveness

For a little while now I’ve had issues with DOM rendering performance within an enterprise-scale product, built using Angular. I’ve always tried to follow some common approaches[note]”3 Tips for Angular Runtime Performance from the Real World.” https://blog.angular.io/3-tips-for-angular-runtime-performance-from-the-real-world-d467fbc8f66e. Accessed 29 Nov. 2019.[/note] to improving and maintaining high performance within an Angular application.

The main approaches I’ve taken to combat performance degradation over time within this application are as follows;

[/vc_column_text][us_separator][vc_column_text]

Working outside the Angular zone

	/**
	 * Loop outside of the Angular zone
	 * so the UI does not refresh after each setTimeout cycle
	 */
	logOutsideOfAngularZone() {
		this.ngZone.runOutsideAngular(() => {
			setTimeout(() => {
				// reenter the Angular zone and display a console log
				this.ngZone.run(() => { console.log('Outside Done!'); });
			});
		});
	}

[/vc_column_text][us_separator][vc_column_text]

Adjusting ChangeDetection Strategies

@Component({
	selector       : 'app-my-component',
	template       : `
		<h1>Title</h1>
	`,
	changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MyComponent implements OnInit, OnDestroy
{
	constructor(private cdRef: ChangeDetectorRef) {}
	public ngOnInit(): void {}
}

[/vc_column_text][us_separator][vc_column_text]

Using trackBy Functions with *ngFor

@Component({
	selector       : 'app-my-component',
	template       : `
		<h1>Title</h1>

		<li *ngFor="let person of people; trackBy:trackByFunction">{{person.name}}</li>
	`,
})
export class MyComponent implements OnInit, OnDestroy
{
	public people: any[] = [
		{ id: 123, name: 'John' },
		{ id: 456, name: 'Doe' },
	];

	constructor() {}
	public ngOnInit(): void {}

	public trackByFunction = (index: number, person: any): number => person.id;
}

While using all these techniques listed above, did result in isolated and localized increases in page performance, I still suffered from an overall application-wide DOM rendering performance problem. This was perceivable to me as what I consider to be page rendering lag whereby elements of the page are visible at given dimensions and positioned a given way, then ping to their correct position and dimensions. Another visible indicator of this issue was noticeable delays in mouse hover queues, such as subtle underlines, CSS animations, and tooltip display.

[/vc_column_text][us_separator][vc_column_text]

The Culprit! my position-to-bottom directive

After further investigation, I discovered that one thing this product made use of that my other products did not, was a directive, the position-to-bottom directive.

export class PositionToBottomDirective implements OnDestroy, AfterViewInit
{
	private readonly ngUnsubscribe: Subject<any> = new Subject();

	constructor(private readonly el: ElementRef, private readonly zone: NgZone) {
		this.el.nativeElement.style.height = 'auto';
	}

	public ngOnDestroy(): void {
		this.ngUnsubscribe.next();
		this.ngUnsubscribe.complete();
	}

	public ngAfterViewInit(): void {
		setTimeout(() => this.calcSize());

		this.zone.runOutsideAngular(() => {
			fromEvent(window, 'resize')
				.pipe(debounceTime(500), takeUntil(this.ngUnsubscribe))
				.subscribe((res: any) => this.calcSize());
		});
	}

	public calcSize(): void {
		let viewport: { top: string };

		this.zone.runOutsideAngular(() => {
			viewport = this.el.nativeElement.getBoundingClientRect()
		});

		const offset: number = parseInt(viewport.top, 10) + 10;
		const height: string = `calc(100vh - ${ offset }px)`;

		this.el.nativeElement.style.overflowY = 'auto';
		this.el.nativeElement.style.height = height;
	}

From the code snippet above, you can see that this directive was relatively simple. Upon initialization and after every browser resizes event, each component this directive was attached to would have it’s height set to the available space within the window.

Use of the RxJS debounceTime[note]”debounceTime · learn-rxjs.” https://www.learnrxjs.io/operators/filtering/debouncetime.html. Accessed 29 Nov. 2019.[/note] and Angular’s runOutsideAngular[note]”NgZone – Angular.” https://angular.io/api/core/NgZone. Accessed 29 Nov. 2019.[/note] the functionality I had hoped to mitigate the impact this directive would have on the performance of the product, as I knew Angular’s change detection will be called for every asynchronous browser event[note]”Angular Change Detection – How Does It Really Work?.” 26 Apr. 2019, https://blog.angular-university.io/how-does-angular-2-change-detection-really-work/. Accessed 29 Nov. 2019.[/note].

Unfortunately, this was not enough so I removed the use of this directive in favor of CSS Flexbox (probably should have used this to begin with :D). After removing the use of this directive I saw a 61% increase in page responsiveness. This was calculated using the top 10 Total time-consuming activities.

[/vc_column_text][us_separator][us_image image=”57792″][vc_column_text]

Top 10 time-consuming activities before removal of this directive

[/vc_column_text][us_separator][us_image image=”57791″][vc_column_text]

Top 10 time-consuming activities after removal of this directive

[/vc_column_text][/vc_column][/vc_row]