Logo

dev-resources.site

for different kinds of informations.

Deferred loading with @defer: Optimize Your App's Performance

Published at
1/15/2025
Categories
angular
webdev
frontend
tutorial
Author
hassantayyab
Categories
4 categories in total
angular
open
webdev
open
frontend
open
tutorial
open
Author
12 person written this
hassantayyab
open
Deferred loading with @defer: Optimize Your App's Performance

Angular continues to innovate with each release, and the introduction of @defer blocks in Angular v19 is a game-changer for optimizing web application performance. This blog post explores Angular's @defer feature, explaining its functionalities, use cases, and practical code examples to help you leverage it effectively.


What are defer Blocks?

Deferrable views, also known as @defer blocks, enable lazy loading for sections of your Angular templates. They reduce the initial bundle size by deferring the loading of code that is not essential for the initial rendering of a page. This improves initial load times and Core Web Vitals (CWV) such as Largest Contentful Paint (LCP) and Time to First Byte (TTFB).

You can declaratively wrap a section of your template in a @defer block to defer its loading:

@defer {
  <large-component />
}
Enter fullscreen mode Exit fullscreen mode

This loads the dependencies of large-component only when required, improving performance.


Key Features of defer Blocks

1. Placeholders for Better User Experience

The @placeholder block lets you show content while the deferred section is being loaded.

@defer {
  <large-component />
} @placeholder {
  <p>Loading...</p>
}
Enter fullscreen mode Exit fullscreen mode

Use Case: Use placeholders to provide immediate feedback to users while content loads.


2. Loading Indicators

The @loading block is shown after the placeholder and during the loading process. It replaces the placeholder content.

@defer {
  <large-component />
} @loading {
  <img alt="Loading..." src="loading.gif" />
} @placeholder {
  <p>Loading...</p>
}
Enter fullscreen mode Exit fullscreen mode

Parameters:

  • minimum: Minimum time to show the loading block.
  • after: Time after loading starts to display the loading block.

Example:

@defer {
  <large-component />
} @loading (minimum 1s; after 100ms) {
  <img alt="Loading..." src="loading.gif" />
}
Enter fullscreen mode Exit fullscreen mode

3. Error Handling

The @error block displays content when deferred loading fails.

@defer {
  <large-component />
} @error {
  <p>Failed to load content. Please try again.</p>
}
Enter fullscreen mode Exit fullscreen mode

Triggers for Controlling Deferred Content

1. Idle Trigger

Defers loading until the browser is idle:

@defer (on idle) {
  <large-component />
} @placeholder {
  <p>Loading...</p>
}
Enter fullscreen mode Exit fullscreen mode

2. Viewport Trigger

Loads content when it enters the viewport:

@defer (on viewport) {
  <large-component />
} @placeholder {
  <p>Scroll down to load...</p>
}
Enter fullscreen mode Exit fullscreen mode

3. Interaction Trigger

Loads content upon user interaction, such as clicks:

@defer (on interaction) {
  <large-component />
} @placeholder {
  <button>Click to load</button>
}
Enter fullscreen mode Exit fullscreen mode

4. Hover Trigger

Loads content when the mouse hovers over a specified area:

@defer (on hover) {
  <large-component />
} @placeholder {
  <p>Hover to load content...</p>
}
Enter fullscreen mode Exit fullscreen mode

5. Timer Trigger

Loads content after a set duration:

@defer (on timer(2s)) {
  <large-component />
} @placeholder {
  <p>Loading in 2 seconds...</p>
}
Enter fullscreen mode Exit fullscreen mode

6. Custom Conditional Trigger

Loads content based on a custom condition:

@defer (when isReady) {
  <large-component />
} @placeholder {
  <p>Waiting for readiness...</p>
}
Enter fullscreen mode Exit fullscreen mode

Combining Prefetching and Deferred Loading

You can specify a prefetch trigger to preload dependencies before they are needed:

@defer (on interaction; prefetch on idle) {
  <large-component />
} @placeholder {
  <button>Click to load</button>
}
Enter fullscreen mode Exit fullscreen mode

This starts prefetching when the browser is idle but only renders the content when the user interacts.


Testing defer Blocks

Angular provides APIs to test @defer blocks using TestBed. You can control and verify different states manually:

it('should test defer block states', async () => {
  TestBed.configureTestingModule({ deferBlockBehavior: DeferBlockBehavior.Manual });

  @Component({
    template: `
      @defer {
        <large-component />
      } @placeholder {
        Placeholder
      } @loading {
        Loading...
      }
    `
  })
  class TestComponent {}

  const fixture = TestBed.createComponent(TestComponent);
  const deferBlock = (await fixture.getDeferBlocks())[0];

  expect(fixture.nativeElement.innerHTML).toContain('Placeholder');
  await deferBlock.render(DeferBlockState.Loading);
  expect(fixture.nativeElement.innerHTML).toContain('Loading...');
  await deferBlock.render(DeferBlockState.Complete);
  expect(fixture.nativeElement.innerHTML).toContain('large-component works!');
});
Enter fullscreen mode Exit fullscreen mode

Best Practices for Using defer Blocks

  1. Avoid Nested Defers: Use distinct triggers for nested @defer blocks to prevent cascading loads.
  2. Prevent Layout Shifts: Avoid deferring components visible during initial load to minimize cumulative layout shift (CLS).

Cheat Sheet for Angular Blocks

  • Basic usage: @defer { <component /> } - Defers the content inside the block.
  • Placeholder: @defer { <cmp /> } @placeholder { <p>Loading...</p> } - Placeholder shown before loading.
  • Loading: @defer { <cmp /> } @loading { <p>Loading...</p> } - Shown during loading process.
  • Error Handling: @defer { <cmp /> } @error { <p>Error...</p> } - Handles loading failures.
  • Triggers: @defer (on idle) - Controls when loading starts.
  • Prefetch: @defer (on interaction; prefetch on idle) - Preloads dependencies early.

Additional Resources

Start exploring Angular's @defer feature today and transform the performance of your Angular applications!

angular Article's
30 articles in total
Favicon
Angular Addicts #33: NgRx 19, using the Page Object Model in tests, Micro Frontends using Vite & more
Favicon
Implantando um aplicativo Angular com DigitalOcean e GitHub de forma gratuita
Favicon
Custom builder for Angular: My way
Favicon
Angular validation common functions
Favicon
Checkout the new @defer in Angular
Favicon
AngularFire Starter Template
Favicon
Deferred loading with @defer: Optimize Your App's Performance
Favicon
🚀 Weekly Angular Challenge: Two Projects a Week!
Favicon
🚀 Weekly Angular Challenge: Two Projects a Week!
Favicon
Use Chrome's Prompt API to generate a trip planner in Angular
Favicon
Don't copy/paste code you don't understand
Favicon
Streamlining Data Flow in Angular: The Power of the Adapter Pattern 🔄
Favicon
Transform Your Web Development Workflow with These JavaScript Giants
Favicon
Breweries App
Favicon
10 Months of Elm to Angular
Favicon
Boost Angular Performance: Lazy Loading Guide
Favicon
🚀 Learning Through Experience: A Tale of NgRx Effects
Favicon
🔥 Effect Stopped Reacting to Action, Have You Ever Faced This? 🔥 I recently learned a valuable lesson about NgRx Effects – specifically, where to place map and catchError when handling service calls.
Favicon
How to create a Google Font Picker in Angular 18
Favicon
MDB Ui kit issue in angular 19
Favicon
Azure App Service doesn't returned compressed (gzip) files for Angular application?
Favicon
Angular form validation directive
Favicon
Unlocking the Power of Angular Signals for Dynamic Reactivity
Favicon
Boosting Your Angular Development Workflow with Cursor Code Editor
Favicon
Eliminate Runtime Errors with Type-safe Routes in Angular
Favicon
[Boost]
Favicon
Ng-News: Angular in 2024
Favicon
Angular Signals and Their Benefits
Favicon
Taming Angular Forms
Favicon
Modify Angular Material 19 Theme with SCSS & CSS

Featured ones: