Optimization & Performance
Last updated
Last updated
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
blockThe 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
blockIs 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.
@loading
blockIs 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
).
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
blockIs an optional block that allows you to declare content that will be shown if deferred loading fails.
Its dependencies are also eagerly loaded.
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.
Alternatively , you can specify a template reference variable
in the same template as @defer
as the element that is watched to enver the viewport.
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.
Alternatively , you can specify a template reference variable
as the element that triggers interaction.
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.
Alternatively , you can specify a template reference variable
as the hover element.
on immediate
Triggers the deferred load immediatly, meaning once the client has finished rendering, the defer chunk would then start fetching right away.
on timer
Would trigger after a specified duration timer(x)
.
The duration can be specified in ms
or s
.
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.
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.
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
.
Enable the Directive.
<img ngSrc="cat.jpg">
, replace the src
attribute with ngSrc
.
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
.
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.
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
.
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}"
.
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.
Angular DevTools, Chrome Web Extension
Go to the Profiler
tab and start Recording
.
As Angular performs change detection in the application, you'll see bars corresponding to the individual change detection cycles.
Each bar shows how much time Angular spent on a detection cycle and what Component was running.
What problem it is.
How to identify it.
How to resolve it.
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.
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.
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.
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>