Getting Started with @defer

Angular's @defer mechanism represents one of the framework's latest performance-oriented additions, specifically targeting lazy loading and render optimization. This section provides a concise summary of the @defer feature as well as the accompanying @placeholder and @loading blocks.

Understanding @defer

Objective

  • The primary goal of @defer is to postpone the loading and rendering of specific components or application segments until they become necessary. This approach can substantially decrease the application's initial load time and boost the overall user experience.

Implementation

  • You can use @defer on individual components or within template sections to mark them for lazy loading. This proves especially valuable in extensive applications or for parts of the UI that aren't immediately visible or essential when a user first visits a page.

Syntax Overview

  • The @defer syntax is simple and fits naturally into Angular's existing template language. The following snippet illustrates its usage:
  @defer {
  <large-component />
  }
Enter fullscreen mode Exit fullscreen mode

Key Benefits

  • Performance Gains: Postponing the load of specific parts of your application can shorten the initial load time, resulting in a snappier and more reactive user experience.
  • Efficient Resource Use: By only fetching components when they're actually required, @defer supports better resource management.
  • UX Improvements: It prioritizes the rendering of vital content first, while less important sections are loaded on demand, which enhances the perceived speed and flow of the application.

Compatibility with Angular

  • @defer works in concert with other Angular capabilities and utilities, enabling developers to apply lazy loading, fine-tune change detection, and utilize other performance strategies in a unified way.

Looking Ahead

  • As Angular develops, the @defer feature is expected to gain more capabilities and improvements. Developers can anticipate having more granular control over the loading and rendering process of their application's components in future versions.

The Role of IntersectionObserver in @defer

At its core, @defer leverages the IntersectionObserver API. This browser API enables you to monitor when a target element's visibility changes relative to an ancestor or the main viewport. By delaying a component's load until it's on the verge of entering the viewport, you can prevent fetching resources for content that might never be seen, thereby saving bandwidth and reducing processing overhead.

Additional IntersectionObserver Advantages

Faster Initial Rendering: Loading only the essential parts upfront ensures the application's first paint is quick. This not only shortens the initial load time but also positively influences how fast and responsive the app feels. Deferred components are assigned their own separate bundles by Angular, which also helps shrink the size of the primary bundle.

Superior User Experience: By preparing content just before it scrolls into view, the browsing experience feels smoother and more cohesive. This strategy is particularly beneficial for pages with lots of scrollable content, as it avoids jank and keeps the application from becoming unresponsive during user interaction.

Optimized for Constrained Environments: Devices with limited processing power or slower internet connections stand to gain significantly from this type of deferred loading. By fetching only what's necessary, these devices can run applications more efficiently, delivering a satisfactory experience across a wider spectrum of hardware.

Practical Demonstrations

Basic @defer Usage

Here’s how you can apply @defer in practice. Start by setting up a component to render images. Keep in mind that using standalone components is a prerequisite for @defer.

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

@Component({
  selector: "app-images",
  standalone: true,
  template: `<div style="display: flex; flex-direction: column;">
    @for(image of list; track image) {
    <img [src]="image" width="600" height="400" />
    }
  </div> `,
})
export class ImagesComponent {
  list = Array(5).fill("https://placehold.co/600x400");
}
Enter fullscreen mode Exit fullscreen mode

The following example shows @defer being used without any extra configuration.

<h1>Angular Defer Sample Application</h1>
@defer () {
<app-images></app-images>
}
Enter fullscreen mode Exit fullscreen mode

If we examine the resulting bundle, it's clear that the image component has been split into its own separate chunk.

Boosting Angular Performance with @defer and Lazy Loading — figure 1

As visible in the network tab upon page load, this particular bundle is fetched at runtime rather than being part of the initial payload.

Boosting Angular Performance with @defer and Lazy Loading — figure 2

Applying @defer with Configuration

There are several configurable options to refine the user experience. Let's look at a few of these below.

The @placeholder Block

When a @defer block is used, its content will render upon entering the viewport. Delays can occur, however, such as when components need to make HTTP requests. This is where the @placeholder block comes in. The placeholder content itself is not lazily loaded. It is displayed immediately and remains visible until the @defer block's contents are fully loaded and ready for display. This block accepts an optional minimum parameter, which dictates how long the placeholder should be shown.

An example implementation would look like this:

<h1>Angular Defer Sample Application</h1>
@defer () {
<app-images></app-images>
} @placeholder (minimum 500ms) {
<p>Loading Images</p>
}
Enter fullscreen mode Exit fullscreen mode

The visual result is demonstrated below:

Boosting Angular Performance with @defer and Lazy Loading — figure 3

The @loading Block

The @loading block displays content once the @defer content has initiated its loading process. This differentiates it from @placeholder, which is shown during the pre-loading phase. Two optional arguments are available for @loading: after and minimum. The minimum argument, as with @placeholder, determines the display duration. The after argument specifies the delay before the loading content appears.

Here's how to configure @loading:

<h1>Angular Defer Sample Application</h1>
@defer () {
<app-images></app-images>
} @loading (after 1s; minimum 500ms) {
<p>Loading Images</p>
}
Enter fullscreen mode Exit fullscreen mode

While the animated GIF might not fully capture it, the configuration instructs the block to wait for at least one second before presenting the loading content, and to keep it visible for a minimum of 500 milliseconds.

Boosting Angular Performance with @defer and Lazy Loading — figure 4

Final Thoughts

Angular's @defer proves to be a significant asset for boosting application performance and UX by postponing component loading until the last possible moment. Combined with additional controls like @placeholder and @loading, developers gain the ability to craft applications that are both more responsive and resource-efficient. With Angular's ongoing innovation, @defer is set to remain a key player in optimizing resource use and enhancing performance standards across various devices and connectivity scenarios.


Stay in Touch

Did this guide help you out? I'd love to hear from you:

🔗 Connect with me on LinkedIn
💻 Explore my GitHub projects
Support my work