10 tips for improving the performance of Angular applications

1) Use Angular CLI’s production build: When building your Angular application for production, use the Angular CLI’s –prod flag. This enables various optimizations, such as AOT (Ahead-of-Time) compilation (latest angular-cli’s have AOT enabled by default), tree shaking, and minification, which can significantly reduce the bundle size and improve runtime performance. Read more about AOT compiler here.

2) Lazy loading: Implement lazy loading for modules in your application. Lazy loading allows you to load modules on demand, reducing the initial bundle size and improving the application’s startup time. Read below step-by-step guide to create the lazy loading modules.

Step 1: Create a feature module

Create a feature module that you want to lazy load. For this example, let’s assume we have a module called DashboardModule.

// dashboard.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';

import { DashboardComponent } from './dashboard.component';

const routes: Routes = [
  {
    path: '',
    component: DashboardComponent
  }
];

@NgModule({
  declarations: [DashboardComponent],
  imports: [CommonModule, RouterModule.forChild(routes)]
})
export class DashboardModule {}

Step 2: Configure lazy loading in the main routing module

In the main routing module (usually app-routing.module.ts), configure lazy loading for the DashboardModule using the loadChildren property of the route.

// app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  {
    path: 'dashboard',
    loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule)
  },
  // Other routes...
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}

Step 3: Update the app component template

Update the app component template (usually app.component.html) to include a link to the lazily loaded module.

<!-- app.component.html -->

<h1>Welcome to the App</h1>

<a routerLink="/dashboard">Go to Dashboard</a>

<router-outlet></router-outlet>

In the above example, when the user clicks on the “Go to Dashboard” link, Angular will load the DashboardModule lazily. This means that the module’s code will be loaded only when the user navigates to the /dashboard route, reducing the initial bundle size and improving the application’s startup time.

Lazy loading is a powerful feature of Angular that helps optimize the loading and performance of your application, particularly when dealing with large and complex projects.

Remember to configure the routes and lazy load the modules based on your application’s specific requirements.

3) Change detection strategy: Consider using ChangeDetectionStrategy.OnPush for components where possible. This strategy allows Angular to perform change detection only when input properties change or when triggered explicitly. It reduces the number of change detection cycles and improves performance.

import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'app-my-component',
  template: `
    <h1>{{ title }}</h1>
    <p>{{ content }}</p>
    <button (click)="updateContent()">Update Content</button>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent implements OnInit {
  title: string;
  content: string;

  ngOnInit() {
    this.title = 'Initial Title';
    this.content = 'Initial Content';
  }

  updateContent() {
    this.content = 'Updated Content';
  }
}

In the above example, the ChangeDetectionStrategy.OnPush is set in the @Component decorator’s changeDetection property. This informs Angular to use the “OnPush” change detection strategy for this component.

With the “OnPush” strategy, change detection will only be triggered when there are changes to the component’s input properties or when explicitly triggered using events like button clicks or HTTP responses. This can help reduce unnecessary change detection cycles for components where the data doesn’t change frequently.

Note: This strategy to work optimally, ensure that the component receives input properties as immutable objects or make use of the Immutable.js library to create immutable objects.

By using the ChangeDetectionStrategy.OnPush strategy, you can optimize the change detection process and improve the performance of your Angular application.

4) TrackBy function: When using Angular’s ngFor directive, provide a trackBy function to optimize rendering. The trackBy function allows Angular to track the identity of items in a list, making updates more efficient and avoiding unnecessary re-rendering of unchanged elements.

import { Component } from '@angular/core';

interface Item {
  id: number;
  name: string;
}

@Component({
  selector: 'app-my-component',
  template: `
    <ul>
      <li *ngFor="let item of items; trackBy: trackByFn">{{ item.name }}</li>
    </ul>
    <button (click)="updateItems()">Update Items</button>
  `
})
export class MyComponent {
  items: Item[];

  constructor() {
    this.items = [
      { id: 1, name: 'Item 1' },
      { id: 2, name: 'Item 2' },
      { id: 3, name: 'Item 3' }
    ];
  }

  trackByFn(index: number, item: Item): number {
    return item.id;
  }

  updateItems() {
    // Simulating an update to the items array
    this.items = [
      { id: 1, name: 'Updated Item 1' },
      { id: 2, name: 'Item 2' },
      { id: 3, name: 'Updated Item 3' }
    ];
  }
}

In the example above, we have an array of Item objects displayed using ngFor in an unordered list (<ul>). We provide a trackBy function in the *ngFor directive to optimize rendering.

The trackByFn function is defined in the component and takes two arguments: the index of the current item and the item itself. In this case, we use the id property of each Item as the unique identifier for tracking.

By providing the trackBy function, Angular can track the identity of each item based on its unique identifier (id in this case). When the array is updated, Angular can identify which items have changed, allowing it to update only the necessary elements in the DOM, rather than re-rendering the entire list.

This optimization can significantly improve the rendering performance, especially when dealing with large lists or when items in the list have complex structures.

Remember to choose a unique identifier for your items that remains stable across updates, such as an id property.

5) Use Angular’s built-in optimization techniques: Take advantage of Angular’s built-in optimization techniques, such as Angular’s built-in directives (ngIf, ngSwitch, etc.), pipes, and template caching. These features are optimized for performance and can help improve the overall application performance.

6) Avoid unnecessary bindings: Minimize the number of two-way data bindings ([(ngModel)]) and event bindings ((click)) in your templates. Excessive bindings can result in unnecessary change detection cycles and impact performance.

7) Use trackBy with ngFor in large lists: When rendering large lists using ngFor, make sure to use the trackBy function and provide a unique identifier for each item. This helps Angular efficiently update the list when items are added, removed, or reordered.

8) Third party libraries: Minimizing the use of third-party libraries and optimizing their usage is an important aspect of improving the performance of Angular applications. Here are a few things to consider:

  1. Bundle size impact: Third-party libraries can significantly contribute to the size of your application bundle. Each library adds its own set of dependencies and code, which can increase the initial loading time of your application. Choose lightweight libraries whenever possible and avoid using multiple libraries that provide similar functionality.
  2. Optimize imports: Import only the necessary modules, components, or functions from a third-party library instead of importing the entire library. This can help reduce the bundle size and improve loading performance. Many libraries provide modularized exports, allowing you to import only the specific parts you need.
  3. Tree shaking: Take advantage of tree shaking, a process that eliminates unused code during the production build. Ensure that your third-party libraries support tree shaking, as this can significantly reduce the bundle size by removing unused code and dependencies.

9) Optimize heavy computations: Avoid performing heavy computations or complex operations within Angular templates. Move such calculations to component classes or services to offload the rendering thread and improve overall performance.

10) Use Angular Performance Tools: Angular provides various performance tools to help identify and optimize performance bottlenecks in your application. These include the Angular DevTools, which provide insights into change detection, component rendering, and memory usage, and tools like Lighthouse, WebPagetest, or Chrome Performance tab for measuring and analyzing application performance.

By following these tips, you can significantly improve the performance of your Angular applications and provide a better user experience. Remember to profile and measure your application’s performance to identify specific areas for improvement and prioritize optimizations based on your application’s needs.

Published by Kumar Gandhi K

Hi! I’m Kumar and I live in Bangalore (IN) with my family. By profession I’m a Web Developer experienced in a vast variety of frameworks and technologies, like, HTML, CSS, JavaScript, Angular, Bootstrap… Using these i have built or sometimes maintained mid market and enterprise level applications. I worked for few software companies over the years and on few domains like finance, field-service and storage. I also did consulting job at one point. I am loyal and hard (or for better word smart) working individual. In my free time I read books, in fact I buy a lot of books hoping that some day I might find all the time in the world to read them and I also enjoy watching TV.

Leave a comment