kdocs
GitHub
Lang - Web
Lang - Web
  • Base
    • Css
    • Javascript
    • Typescript
      • New Project
  • Frameworks
    • Angular
      • Directives
      • Components
      • Templates
        • Bindings
        • Control Flow
        • Variables
      • Signals
      • Pipes
      • Services
        • Dependency Injection
      • Forms
        • Reactive Form
        • Template-Driven Form
      • Router
      • HTTP Client
      • Observables RxJS
      • Testing
        • Components
        • Directives
        • Pipes
        • Services
      • Optimization & Performance
      • Security
Powered by GitBook
On this page
  • Deferrable Views
  • @defer block
  • @placeholder block
  • @loading block
  • @error block
  • Triggers
  • Prefetching
  • Testing
  • Image Optimization NgOptimizedImage
  • Runtime Performance Optimization
  • Optimizing Injection Tokens
  1. Frameworks
  2. Angular

Optimization & Performance

PreviousServicesNextSecurity

Last updated 5 months ago

Deferrable Views

  • Can be used in component template to defer the loading of select dependencies within that template.

    • These dependencies may include components, directives, pipes, and associated CSS.

  • They are powerful tool used to refuce the initial bundle size or defer heavy components that may not ever be loaded until a later time.

  • To use this, you can wrap a section of your template in a @defer block which specifies loading conditions.

  • Deferrable views support a series of triggers, prefetching and several sub blocks used for placeholder, loading and error state management.

It is highly recommended that any defer loaded component that might result in layout shift once the dependecies have loaded be below the fold or otherwise not yet visible to the user.

In order for dependencies to be deferrable they must:

  • Be standalone. Non-standalone dependencies cannot be deffered and will still be eagerly loaded, even if inside @defer blocks.

  • They must not be directly referenced from the same file, outside of @defer blocks; this includes ViewChild queries.

Behavior with Server-side Rendering:

  • @defer blocks always render their @placeholder (or nothing if not specified).

  • Triggers are ignored on the server.

@defer block

  • The content of the main @defer block is the section of content that is lazily loaded.

  • All of the content will appear once the specified trigger or when condition is met and the dependencies have been fetched.

  • By default, a @defer block is triggered when the browser state becomes idle.

Nested @defer blocks (avoiding cascading loads)

There are cases where nesting multiple @defer blocks may cause cascading requests. An example of this would be when a @defer block with an immediate trigger has a nested @defer block with another immediate trigger. When you have nested @defer blocks, make sure that an inner one has a different set of conditions, so that they don't trigger at the same time, causing cascading requests.

@placeholder block

  • Is an optional block that declares content to show before the defer block is triggered.

  • This placeholder content is replaced with the main content once the loading is complete.

  • You can use any content in the placeholder including, plain HTML, components, directives, pipes.

    • Just keep in mind that dependencies of the placeholder are eagerly loaded.

minimum parameter (optional)

  • Is specifed in time increments of miliseconds (ms) or seconds (s).

  • It exists to prevent fast flickering of placeholder content in the case that the deferrable dependecies are fetched quickly.

@defer {
    <large-component />
} @placeholder (minimum 500ms) {
    <p>Placeholder content</p>
}

@loading block

  • Is an optional block that allows you to declare content that will be shown during the loading of any deferred dependencies.

  • Its dependencies ae also eagerly loaded (similar to @placeholder).

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

minimum parameter (optional)

  • Is specifed in time increments of miliseconds (ms) or seconds (s).

  • To specify the minimum amount of time that this placeholder should be shown.

after parameter (optional)

  • Is specifed in time increments of miliseconds (ms) or seconds (s).

  • The amount of time to wait after the loading begins before showing the loading template.

@error block

  • Is an optional block that allows you to declare content that will be shown if deferred loading fails.

  • Its dependencies are also eagerly loaded.

@defer {
    <calendar-cmp />
} @error {
    <p>Failed to load the calendar</p>
}

Triggers

  • There are two options for configuring when a swap is triggered: on and when.

on

  • Specifies a trigger condition using a trigger from the list of available triggers bellow.

  • Multiple triggers can be defined at once. For instance: on interaction; on timer(5s) means that the defer block will be triggered if the user interacts with the placeholder, or after 5 seconds.

  • Multiple on triggers are always OR conditions. Similarly, on mixed with when conditions are also OR conditions.

on iddle

  • Will trigger once the browser has reached an idle state (detected using requestIdleCallback API under the hood).

  • Is the default behavior.

on viewport

  • Will trigger when the specified content enters the viewport.

  • By default the @placeholder will act as the element watched for entering the viewport as long as it is a single root element node.

@defer (on viewport) {
    <calendar-cmp />
} @placeholder {
    <div>Calendar placeholder</div>
}
  • Alternatively , you can specify a template reference variable in the same template as @defer as the element that is watched to enver the viewport.

<div #greeting>Hello!</div>

@defer (on viewport(greeting)) {
    <greetings-cmp />
}

on interaction

  • Will trigger when the user interacts with the specified element through click or keydown events.

  • By default, the placeholder will act as the interaction element as long as it is a single root element node.

@defer (on interaction) {
    <calendar-cmp />
} @placeholder {
    <div>Calendar placeholder</div>
}
  • Alternatively , you can specify a template reference variable as the element that triggers interaction.

<button type="button" #greeting>Hello!</button>

@defer (on interaction(greeting)) {
    <calendar-cmp />
} @placeholder {
    <div>Calendar placeholder</div>
}

on hover

  • hover triggers deferred loading when the mouse has hovered over the trigger area.

    • Events used for this are mouseenter and focusin.

  • By default, the placeholder will act as the hover element as long as it is a single root element node.

@defer (on hover) {
    <calendar-cmp />
} @placeholder {
    <div>Calendar placeholder</div>
}
  • Alternatively , you can specify a template reference variable as the hover element.

<div #greeting>Hello!</div>
@defer (on hover(greeting)) {
    <calendar-cmp />
} @placeholder {
    <div>Calendar placeholder</div>
}

on immediate

  • Triggers the deferred load immediatly, meaning once the client has finished rendering, the defer chunk would then start fetching right away.

@defer (on immediate) {
    <calendar-cmp />
} @placeholder {
    <div>Calendar placeholder</div>
}

on timer

  • Would trigger after a specified duration timer(x).

  • The duration can be specified in ms or s.

@defer (on timer(500ms)) {
    <calendar-cmp />
}

when

  • Specifies a condition as an expression that returns a boolean.

  • When the expression becomes truthy, the placeholder is swapped with the content.

  • If the when condition switches back to false, the defer block is NOT reverted back to the placeholder.

Prefetching

  • Defer allows to specify conditions when prefetching of the dependencies should be triggered.

  • when and on are associated with defer controls when to render. prefetch when and prefetch on controls when to fetch the resources.

  • This allows for more advanced behaviors, such as letting you start to prefetch resources before a user has actually seen or interacted with a defer block, making the resources available faster.

In the example below, the prefetching starts when a browser becomes idle and the contents of the block is rendered on interaction.

@defer (on interaction; prefetch on idle) {
    <calendar-cmp />
} @placeholder {
    <img src="placeholder.png" />
}

Testing

Image Optimization NgOptimizedImage

  • The NgOptimizedImage directive makes it easy to adopt performance best practices for loading images.

  • Do not use background images in CSS, convert them to absolute components which can use NgOptimizedImage.

Getting Started

  1. Enable the Directive.

    • <img ngSrc="cat.jpg">, replace the src attribute with ngSrc.

  2. Mark images as priority.

    • <img ngSrc="cat.jpg" priority>

    • This will apply optimizations like:

      • fetchpriority=high

      • loading=eager

      • Automatically generate a preload link element if rendering on the server.

    • By default non-priority images will have loading=lazy.

  3. Include width and height.

    • For responsive images, the values should be the intrinsic size of the image file. It is also important to set sizes.

    • For fixed sized images, the values should reflect the desired rendered size of the image.

      • The aspect ratio should always match the intrinsic aspect ratio of the image.

Using fill mode (background image behavior)

  • Use it for cases you want to have an image fill a containing element.

  • When using fill attribute, you must not include width and height attributes.

  • For the fill image to render properly, its parent element must have position: relative, position: fixed or position: absolute.

<img ngSrc="cat.jpg" fill />

Placeholder placeholder

  • NgOptimizedImage can display an automatic low-resolution placeholder for your image if you're using a CDN or image host that provides automatic image resizing.

  • Adding this attribute automatically requests a second, smaller version of the image using your specified image loader.

    • You can also specify a base64 without an image loader with placeholder="data:image/[imagetype];[data]".

    • Keep in mind that large data URLs increase the size of bundles and slow down page load.

  • The placeholder will also apply a blur effect to this small image.

    • To render without this effect you may provide a second attribute [placeholderConfig]="{blur: false}".

<img ngSrc="cat.jpg" width="400" height="200" placeholder />

Configuring a Image Loader

Runtime Performance Optimization

  • Change detection is highly optimized and performant, but it can still cause slowdowns if the application runs it too frequently.

  • How to control and optimize the change detection mechanism by skipping parts of your application and running change detection only when necessary.

How to Profile an Application - with Angular DevTools, Chrome Web Extension

  1. Go to the Profiler tab and start Recording.

  2. As Angular performs change detection in the application, you'll see bars corresponding to the individual change detection cycles.

  3. Each bar shows how much time Angular spent on a detection cycle and what Component was running.

Performance Pattern

  • What problem it is.

  • How to identify it.

  • How to resolve it.

Zone Pollution

  • This happens when Angular zone wraps callbacks that trigger redundant change detection cycles.

  • Polluting the zone happens when we run an initialization logic that uses requestAnimationFrame, setTimout or addEventListener.

  • You can identify this problem, by looking for unexpected change detection cycles in the Profile output.

  • The solution is to move initializations outside the Angular zone.

For example, you may initialize a chart, and see that interations with the chart bars, are triggering change detection cycles that are useless.

export class Component implements OnInit {
    constructor(private zone: NgZone) {}

    ngOnInit() {
        // Now interations with the chart will not trigger change detection
        this.zone.runOutsideAngular(() => SomePlotChart("chart", data));
    }
}

Out of Bounds

  • This happens when local state changes triggers out of bounds change detection.

    • Meaning that changes in one place may trigger detection changes of other unrelated places.

  • You can identify this problem, by change detection performed in components outside the scope of the change.

  • The solution is to use OnPush change dectection and consider refactor.

Recalculation (of referentially transparent expressions)

  • This happens when Angular recalculates the same template expression repeatedly, even though they depend only on parementers that values does not change. (Redundant calculations)

  • You can identify this problem, when detection for changes takes longer than expected given the state changes.

  • The solution involves either pipes or memoization of these values.

Large component trees

  • You may observe framedrops if you have complex component trees with a lot of instances.

  • The solution involves making the tree smaller, with techniques like on-demand rendering, with like virtualization or pagination.

    • <cdk-virtual-scroll-viewport>

Optimizing Injection Tokens
AngularAngular
AngularAngular
AngularAngular
AngularAngular
Defer
AngularAngular
Logo
Logo
Logo
Logo
Logo