Lightning Components Performance Best Practices
Lightning Components Performance Best Practices
Best Practices
Lightning Components run at the client-side, in a single page (where they are
created and destroyed as needed), and alongside other components that work on
the same data. In this blog post, we discuss how these characteristics impact
performance, and review a list of best practices to optimize the performance of your
Lightning Components.
If you are just starting with Lightning components, consider completing the following
Trailhead modules before diving deeper:
• Data retrieval
• Data caching
• Component instantiation
• Conditional rendering
• Data binding
• Lists (aura:iteration)
• Events
• Image optimization
Data retrieval
Optimize server round-trips:
• Before making a call to the server, make sure there’s no other option to obtain
the data.
• When making a call to the server, limit the columns and rows of the result set:
• Lazy load occasionally accessed data. Don’t preload data that the user may
never ask for (for example, data hidden behind a tab the user may not click, or
in a combobox the user may not open).
• Client-side filtering and sorting: Don’t make a call to the server to filter or sort
data you already have at the client-side.
Data caching
Application composition is a powerful way to build apps by assembling self-contained
components. However, without proper planning, the autonomous nature of the
components you assemble can have an adverse impact on performance. For
example, if all the components you build make their own isolated calls to the server
to retrieve the data they need, you’ll probably end up with lots of redundant server
calls, which can dramatically impact performance.
Client-side data caching can solve that problem by sharing data among components.
This can significantly reduce the number of server round-trips, and improve the
performance of your Lightning components. The Lightning Component Framework
has two built-in mechanisms for client-side caching (storable actions and Lightning
Data Service). You can also implement a custom caching solution.
Storable actions
A storable action is a server action whose response is stored in the client cache so
that subsequent requests for the same server method with the same set of
arguments can be accessed from that cache. Server actions enable you to access
data using a traditional rpc approach: You implement some logic in Apex that you
expose as a remotely invocable method. Storable actions enable you to cache
virtually anything (whatever the server method call returns): a record, a collection of
records, a composite object, a custom data structure, data returned by a callout to a
third-party service, and so on.
The general guideline is to cache (mark as storable) any action that is idempotent
and non-mutating.
More information:
• Check out the DreamHouse sample application for examples. Storable actions
are used in the following
components: PropertyListDaysOnMarketChart, PropertyTileList,
and SimilarProperties
Custom cache
You can also implement your own custom cache approach. As always, make sure
you don’t reinvent the wheel and only use a custom cache approach when there is
no standard way to implement your caching requirements in the framework. For
example, a custom cache can be a good solution for static data like a list of states in
the United States, picklist values, and so on. You can use a storable action in this
case too, but it still generates unneeded server calls (every time the data in the
cache is older than the refreshAge, currently set to 30 seconds in the framework). If
you know that the data won’t change, or changes infrequently, you can implement a
custom cache solution that retrieves the data once after the user logs in and then
never goes back to the server.
Check out the Mutual Fund Explorer app for an example of a custom cache. Open
the DataCache static resource (File > Open > Static Resource > Data Cache in
the developer console). And then check out
the SectorSelector and AssetClassSelector components to see how it’s used to
cache the list of sectors and asset classes.
More information:
Read the Modularizing Code in Lightning Components blog post for strategies to
implement a custom cache.
Summary of client-side caching options:
Collections of records, composite responses, custom data structures, third-party data Storable actions
Complete control over caching implementation Custom cache
Component instantiation
Showing every available piece of data and every available tool on the screen just in
case the user may need it is generally not considered a good UI practice. It can also
significantly impact the performance of your application. Today’s interactive design
guidelines favor progressive disclosure.
“Progressive disclosure is an interaction design technique often used in human
computer interaction to help maintain the focus of a user’s attention by reducing
clutter, confusion, and cognitive workload. This improves usability by presenting only
the minimum data required for the task at hand” (Wikipedia). Put another way,
“progressive disclosure defers advanced or rarely used features to a secondary
screen, making applications easier to learn and less error-prone” (Jakob Nielsen).
In Lightning Experience, it’s easy to implement progressive disclosure and defer the
data or features that aren’t essential to the task at hand. Let’s take a closer look at
two approaches to defer component creation.
• Utility Bar
Conditional rendering
There are two popular techniques to conditionally render UI elements:
Data binding
There are two ways to establish a connection between UI elements and attributes:
bound and unbound expressions.
Lists (aura:iteration)
When creating custom list components (typically using <aura:iteration>), don’t
support the creation of an infinite number of list items. Either provide a pagination
mechanism, or virtualize the list (reuse and rehydrate a limited number of list item
components).
Check out the Paginator component along with the PropertyController Apex class
in DreamHouse for an example of a paginated list.
Events
Minimize the number of event handlers:
• <Paginator onPageNext="{!c.pageNextHandler}"
• onPagePrevious="{!c.pagePreviousHandler}"/>
• Use attributes or <aura:method> for parent-to-child communication
• When working with lists, letting events bubble, and registering a single event
listener on a parent element instead of a separate event listener on every list
item can significantly reduce the number of event listeners in your application,
which can have a positive impact on performance. In the Mutual Fund Explorer
application check out the FundTileList component, and see how a
single onmousemove event listener is registered on the list element (<ul>)
instead of a separate listener on every list item (<li>) (inside
the FundTile component).
More information:
• The original components that were made available when the Lightning
Component Framework first came out live in the ui namespace
(<ui:button>, <ui:inputText>, and so on).
• The new and improved components, also known as the Base Lightning
Components, live in the lightning namespace
(<lightning:button>, <lightning:input>, and so on).
• Styles: Base Lightning Components are styled with the native Lightning look
and feel.
Image optimization
• When possible, use the (sprite-based) Lightning Design System icons
(using <lightning:icon> and <lightning:buttonIcon>) instead of
custom icons.
• Lock image dimensions (to avoid reflows) and serve the image in those
dimensions when possible. For example, don’t load a high-resolution image to
display a thumbnail.
Debug mode On