Types of Loading in Angular
Eager Loading, Lazy Loading, and Preloading are three key module loading strategies in Angular. These strategies determine how and when modules are loaded in an application. Let’s explore each of them with examples:
1. Eager Loading:
Eager loading is the default loading strategy in Angular. This method loads all modules when the application launches, regardless of whether they are immediately needed.
2. Lazy Loading:
Lazy loading loads modules only when they are needed. This can improve the application’s loading time and significantly reduce the initial bundle size, especially for large applications.
3. Pre-Loading:
Feature modules using Preloading are automatically loaded in the background after the application starts. This strategy combines the benefits of Eager Loading and Lazy Loading.
Let’s check it in detail
Eager Loading
As we now know, this loading technique loads all the modules at the beginning of the application, i.e., during the startup, without considering whether a module is immediately required or not. This can result in larger initial bundle sizes, potentially impacting the application’s loading speed.
Advantages:
- All modules are loaded at the beginning, eliminating the need to load them repeatedly.
- It ensures the application runs smoothly since all modules are already available.
Disadvantages:
- All modules are loaded at the beginning, resulting in a larger bundle size, which can slow down the application’s initial loading time.
- For large and complex applications, the heavy bundle load may cause performance issues or even lead to crashes.
When to use Eager loading
- In small-sized applications, the program will be quicker and more responsive to processing requests if all modules are loaded before the application launches.
- The required features and core modules for the application’s launch may include the first page’s components, interceptors (for authorization, authentication, and error handling), error response components, top-level routing, localization, and other essential features. To ensure the application runs smoothly, regardless of its size, we should load these modules with careful consideration.
Example:
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { HomeComponent } from './home/home.component'; import { AccountComponent } from './account/account.component'; import { CustomersComponent } from './customers/customers.component'; const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'home', component: HomeComponent }, { path: 'account', component: AccountComponent }, { path: 'customers', component: CustomersComponent }, { path: '**', component: HomeComponent } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
From the above code snippet, we can illustrate that all components are loaded at the beginning, even though the application initially displays only the home page. Components like the account section may or may not be visited by the user, but they are still loaded at the start. This loading process makes the application slower and consumes more space.
Live example on stackblitz.
Lazy Loading
This technique promotes the idea of “being lazy,” meaning work is done only when required. Similarly, modules are loaded using the lazy loading mechanism as and when they are needed. This can significantly speed up the application’s loading time and drastically reduce the initial bundle size, especially for large applications.
Advantages:
- Required modules are loaded at the beginning, eliminating the worry of loading all modules at once.
- Smaller bundle size results in faster loading.
- Best suited for large and complex applications due to modular loading.
Disadvantages:
- Careful routing setup is necessary to ensure that the required modules for starting the app are loaded.
- Not all modules can be lazy-loaded.
When to use lazy loading:
- Applying lazy loading in this scenario is a simple and straightforward process. When a large-scale web application launches, all other modules that are not immediately needed can be loaded later.
- It is particularly useful for vast and complex applications with multiple modules.
Example:
//App.module.ts import { HttpClientModule } from '@angular/common/http'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, FormsModule, HttpClientModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
//app-routing.module.ts import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = [ { path: 'orders', loadChildren: () => import('./orders/orders.module').then(m => m.OrdersModule) }, ]; @NgModule({ imports: [ RouterModule.forRoot(routes) ], exports: [RouterModule], providers: [] }) export class AppRoutingModule { }
// orders-routing.module.ts import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { OrdersComponent } from './orders.component'; const routes: Routes = [ { path: '', component: OrdersComponent } ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class OrdersRoutingModule { }
// order.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { OrdersRoutingModule } from './orders-routing.module'; import { OrdersComponent } from './orders.component'; @NgModule({ imports: [ CommonModule, OrdersRoutingModule ], declarations: [OrdersComponent] }) export class OrdersModule { }
From the above snippets, we can illustrate that the required modules will load at the application’s start, while the modules specified with loadChildren will be dynamically loaded when the user visits the corresponding route. Until the user accesses the specified route, those components are not required and are not loaded into memory, making the application faster with a smaller bundle size.
For demo, refer stackblitz.
Pre-Loading
It is one of the loading strategies that is rarely used compared to Eager Loading and Lazy Loading. Pre-loading is not frequently used in web application development. In this strategy, feature modules specified for Pre-Loading are automatically loaded after the application starts. All designated modules are preloaded in advance, ensuring quicker access when needed.
Advantages:
- All modules are loaded one by one as specified after the application starts.
- It preloads components that the user is likely to visit next, improving responsiveness.
Disadvantages:
- All modules are loaded at the beginning, resulting in a larger bundle size, which can slow down the initial loading speed.
- For large and complex applications, it may cause performance issues or even break due to the heavy bundle load.
When to use pre-loading:
- Medium-Sized Applications: Since the remaining modules will load later, the application can start faster. Additionally, once the application has started, it will respond to user requests more quickly than if it used the lazy loading technique.
- Predictable Module Usage: If certain modules are likely to be used soon after the application launches, pre-loading them can enhance responsiveness. Other modules can still be lazy-loaded as needed.
- Clear Next Component Prediction: If the next component a user is likely to visit is predictable, pre-loading can be beneficial to ensure a smoother experience.
There are 2 strategies for pre-loading the module
a) Preloading all module
//App-routing.module.ts import { NgModule } from "@angular/core"; import { Routes, RouterModule } from "@angular/router"; import {PreloadAllModules } from '@angular/router'; const routes: Routes = [ { path: "login", loadChildren: () => import("./auth/auth.module").then(m => m.AuthModule), data: { preload: true, delay: true, time: 5000 } }, ]; @NgModule({ imports: [ RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }) ], exports: [RouterModule] }) export class AppRoutingModule {}
b) Preloading with custom strategy
//App-routing.module.ts import { NgModule } from "@angular/core"; import { Routes, RouterModule } from "@angular/router"; import { CustomPreloadingStrategyWithDelay } from "./core/custom-preloading-strategy-with-delay"; const routes: Routes = [ { path: "login", loadChildren: () => import("./auth/auth.module").then(m => m.AuthModule), data: { preload: true, delay: true, time: 5000 } }, ]; @NgModule({ imports: [ RouterModule.forRoot(routes, { preloadingStrategy: CustomPreloadingStrategyWithDelay }) ], exports: [RouterModule] }) export class AppRoutingModule {}
//custom-preloading-strategy-with-delay.ts import { PreloadingStrategy, Route } from "@angular/router"; import { Injectable } from "@angular/core"; import { Observable, of, timer } from "rxjs"; import { flatMap } from "rxjs/operators"; @Injectable({ providedIn: "root" }) export class CustomPreloadingStrategyWithDelay implements PreloadingStrategy { preload(route: Route, load): Observable<any> { const loadRoute = (delay, time) => delay ? timer(time ? time : 1000).pipe(flatMap(_ => load())) : load(); return route.data && route.data.preload ? loadRoute(route.data.delay, route.data.time) : of(null); } }
From the above code snippet, we can illustrate that any module can be loaded in advance if we predict that the user will visit the next page. This can be achieved by specifying the preload value for the module during route configuration.
If we are unsure about which module to preload, we can configure all modules for preloading. However, if we have a good idea of the pages likely to be visited in a particular order, we can implement a custom preload strategy to load the modules accordingly.
For example refer preload all module strategy stackblitz.
For example refer custom preload strategy stackblitz.
Conclusion
Efficient loading strategies are essential for optimizing Angular applications. By understanding and applying the right approach — whether it’s Eager Loading, Preloading, or Lazy Loading — developers can create applications that are both performant and scalable.
- Eager Loading is ideal for small to medium-sized applications or for modules that are critical for the initial user experience. It ensures that all necessary resources are available immediately upon launch.
- Lazy Loading is a great choice for large-scale applications with multiple modules, as it defers loading until the user navigates to specific sections. This minimizes the initial load time and reduces memory consumption.
- Preloading offers a balanced approach by intelligently loading modules in the background, enhancing responsiveness for expected user journeys. This is particularly useful when user navigation patterns are predictable.
Choosing the right loading strategy depends on the application’s complexity, expected user behavior, and performance requirements. By leveraging these techniques effectively, developers can improve loading times, reduce resource consumption, and ensure a seamless user experience. Additionally, using a combination of these strategies can further optimize the application’s overall performance.