Latest Ext JS 7.8 is now available. Learn more

Performance Optimization for Layout Runs

April 21, 2016 264 Views
Show

If an Ext JS application starts to show performance issues, there are always a few usual suspects that developers should focus their investigation on. In broad categories, they are network limitations (bandwidth and latency), device memory/storage limitations, and layout/rendering issues.

In this post, we will only cover optimizing the layout and rendering process of Ext JS Classic Toolkit applications, also known as a Layout Run. Layout and rendering issues typically occur when an application grows to include dozens of components in a single container view, triggering unnecessary layout runs. You may use a JS Framework to Debug, Troubleshoot, and Improve the Performance of Your Apps to aid in performance optimization when running layout runs.

Understanding a Layout Run

When an Ext JS container class is initialized, it begins a process to initialize and wire together all the components that are a part of the container view. To optimize rendering and layout performance of the container and its components, the goal is to avoid recomputing CSS / style and rendering calculations which occur by adding, subtracting, or modifying elements on the DOM. The browser caches these style calculations, but the style values will likely need to be recomputed each time a new component is added, subtracted, or modified in its container. This is why Ext JS 6 renders components in bulk, instead of rendering each component separately. Bulk rendering creates an entire component tree as HTML, and then writes it to the DOM with one stroke. After rendering, Ext JS begins a process known as a Layout Run, which computes the size and position of unknown layout and style values for some components on the viewport. Layout / Style values for components that use auto, flex, or other dynamic values are unknown and may need to be computed based on values from other components. To improve performance, developers should try to minimize unnecessary layout runs, which leads to re-computations and sluggishness.

Detecting a Layout Run

To remove unnecessary layout runs, you first need to find them. There are two easy ways to detect a layout run. First, Sencha Inspector has the ability to watch for it. The third tab in the Sencha Inspector header is dedicated to helping developers watch for layout runs. To start watching, simply click on the Watch button. After a new layout run is triggered, it will appear in the list with the list of components that were affected.

Performance Optimizations for Layout Runs - Sencha Inspector

Figure 1: An event has triggered four layout runs in this sample which can likely be contracted into one layout run.

The second way to detect a layout run is to copy and paste the following line of code into Google Chrome Console:

Ext.Function.interceptBefore(Ext.layout.Context.prototype, 'run', function () {
    console.log('Layout run');
    debugger;
});

This line of code intercepts each call to a layout run, and triggers a breakpoint with a call to a debugger keyword. Because the debugger keyword is equivalent to setting a breakpoint, the code execution is halted; this enables the developer to check the Call Stack and determine which methods triggered the layout run. Figure 2 contains an example where the line of code to intercept the layout run is placed into the debugger. After a new tab in a tab panel is activated, the console log outputs “Layout Run” and a breakpoint is triggered. The Call Stack can be traced to find the event that triggered the layout run. In this case, there was only one layout run triggered for a tab panel active event, which is great!

Performance Optimizations for Layout Runs - Chrome Developer Console

Figure 2: Chrome Developer Console shows a breakpoint triggered by a debugger statement after a new tab from a tab panel is activated.

Optimizing Layout Performance

If you detect that a single action or event is triggering several layout runs, it’s likely that there’s an opportunity to optimize. Quite often, this occurs when you add multiple components individually after the container view is already rendered. Adding each new component to a container view triggers a new layout run. If multiple components need to be added, you can suspend a layout run by calling the Ext.suspendLayouts() method. Once all the desired components are added or modified in container view, you should then resume the layout run via Ext.resumeLayouts(true) method.

If an event does trigger a new layout run, you can further manage performance impacts by setting the size (width and height) of the modified component’s container to a static value. This can reduce the impact because the layout run no longer has to consider how modifying the component will affect adjacent containers and their size and layout.

Sencha Inspector is available to try for free as a part of the Ext JS trial. You can learn more about Sencha Inspector.

Try out these performance improvements and share your experience in the comments below.