# Optimization & Performance

## Deferrable Views

{% embed url="<https://angular.dev/guide/defer>" %}
Defer
{% endembed %}

* 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.

```html
@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`).

```html
@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.

```html
@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.

```html
@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.

```html
<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.

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

* Alternatively , you can specify a `template reference variable` as the element that triggers interaction.

```html
<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.

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

* Alternatively , you can specify a `template reference variable` as the hover element.

```html
<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.

```html
@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`.

```html
@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.*

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

### Testing

{% embed url="<https://angular.dev/guide/defer#testing>" %}

<br>

## Image Optimization `NgOptimizedImage`

{% embed url="<https://angular.dev/guide/image-optimization>" %}

* 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`.

```html
<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}"`.

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

#### Configuring a Image Loader

{% embed url="<https://angular.dev/guide/image-optimization#configuring-an-image-loader-for-ngoptimizedimage>" %}

<br>

## Runtime Performance Optimization

{% embed url="<https://angular.dev/best-practices/runtime-performance>" %}

* 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.*

```typescript
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](https://angular.dev/guide/di/lightweight-injection-tokens)
