Latest Ext JS 7.8 is now available. Learn more

What’s Coming in Ext JS 4.1

December 5, 2011 1042 Views
Show

What's New in Ext JS 4.1

h4. Update (12/23): Ext JS 4.1 Beta 1 is now available

Download Ext JS 4.1 Beta 1
more info

The upcoming Ext JS 4.1 release prioritizes performance. We’ve been working hard to improve across the board, but we’ve focused on two major areas: rendering and layout. While this has taken up the majority of our time, there have been many other exciting developments to report. Among these are significant improvements to the JS Grid and border layout, as well as a preview of the new Neptune theme. Read on as to what Ext Js improves in the new beta version.

Learn the latest about Ext JS and HTML5/JavaScript for three intensive days with 60+ sessions, 3+ parties and more at SenchaCon 2013. Register today!

h3. Performance

The necessary precursor to improving performance is measuring it. To successfully and permanently increase performance, however, measurement has to become part of the regular build and test process. This was the first piece we put in place for Ext JS 4.1. Going beyond the use of profilers like dynaTrace, we created some simple measurement tools to use on a continuous basis. We use these tools to track key metrics on every build.

The performance metrics we track correspond to the page life cycle: Load, Initialize, Render and Layout.

h4. Load

An Ext JS application comes to life when its “onReady” function is called. Prior to that time, many things have to take place. When we say “page load”, we can mean many different things, but for the sake of simplicity, here we define page load as the time period that starts at the execution of the first line of “ext-all.js” and ends just before any onReady functions are called. This primarily includes time spent executing all of the Ext.define statements that populate the Ext namespace, and also the detection of when the page’s DOM is ready.

h4. Initialize

When the onReady functions are called, the application takes over. Applications perform whatever custom initialization they may need, but at some point they will create components and containers to display. In some applications, there will be literally hundreds of components created. Each of these components and containers has to be constructed, initialized and wired together.

In Ext JS 4, many more things are components compared with previous releases. Consider the header of a panel. The Header component is actually a container that contains a basic component for the title and (optionally) a set of Tool components: all managed by an hbox layout. This means you can add components to the panel’s header quite easily. It also means that there are more components and containers created in Ext JS 4 given the same panel configuration. Looking at the Themes example in Ext JS 3, there were 148 components in 50 containers. That same configuration in Ext JS 4 generates 271 components in 97 containers. This makes optimization of this area essential.

h4. Render

The next step is the conversion of these initialized components and containers into HTML. In previous versions of Ext JS, rendering was a mixture of calls to the createElement API and setting innerHTML. In Ext JS 4.0, each component’s primary element was created using createElement and its internal structure was produced using an XTemplate instance referred to as the “renderTpl”.

If a component happened to be a container such as a Panel, additional elements were created using createElement and the child components repeated the process as they rendered into the panel’s body element. At each step, special component methods were called and events were fired to allow derived classes and applications to extend this process.

In version Ext JS 4.1 we have optimized component rendering, so components are rendered in bulk. Instead of alternating calls to createElement and innerHTML, bulk rendering creates the entire component tree as HTML and then adds it to the DOM with a single write to innerHTML.

Figure 1: Render Process
Figure 1: Render Process

To support this change we added a new method to components called “beforeRender”. There has always been the “beforerender” event, but derived classes typically had to choose between overriding the “render” or “onRender” method if they needed to do any work just before their primary element was created. They could do what they needed and then call the base version of the method which would then create the element.

The general flow of rendering in 4.0 vs 4.1 is shown in Figure 1. In both cases, the process starts at a particular component and descends the component tree.

h4. Layout

Once the DOM has all the necessary elements, the final step is to determine the size and position of any elements that need special handling. Or in other words: the final step is to lay out the components. This process is the most complex and time consuming. It represented just over half the total time in loading the Themes example in 4.0.7. The challenge with layouts comes from how browsers handle requests for style information (such as margins, width and height), especially if these are being changed along the way.

The first rule of performance is that CSS calculations are expensive. Because of this, browsers cache these results. When JavaScript comes along and sets a width or height, however, the browser has to invalidate some or all of this cache. How much of the cache this affects is a function of what was changed and the cleverness of the browser’s CSS engine. The next request for style information will typically then trigger a “reflow” to refresh the cache. In general, one could say “write + read = reflow”. Given that reflows are expensive, an obvious way to increase performance is to reduce the number of reflows that occur during a layout.

In Ext JS 4.0, an hbox layout, for example, buffered all of its calculations and wrote those results only after it had read all that it needed from each component. If the hbox needed to know the size of a component, it had to measure the component’s element (read), but before it could do that, the layout of that component had to do its work first. In other words, the component’s layout performed some calculations (reads) and then stored the results to the DOM (writes). The hbox then measured the component’s element (read).

What started out as a sequence of reads followed by a sequence of writes often became a highly interleaved set of reads and writes, which, of course, resulted in a large number of reflows. To eliminate these reflows the child layouts needed a way – external to the DOM – to report their results to their owner.

Layouts in Ext JS 4.1 have been refactored to use a layout context object to share results while avoiding the write/read to the DOM (and its associated reflow). This change, while largely internal, breaks custom layouts. While we believe this is a fairly rare practice, it is something to be aware of when upgrading.

h4. From 4.0.7 to 4.1 PR1

All of these optimizations produced some very significant gains. One of the key examples used to benchmark the performance of Ext JS is the Themes example. The performance difference of 4.1 PR1 compared to 4.0.7 in this example is shown in Figure 2, as tested on IE8.

Figure 2: Themes Example Performance

h4. Next Steps

While 4.1 is clearly a big improvement over 4.0, it is not yet as fast across the board as 3.4. This is not the last word on optimizing performance. In fact, we have many other performance optimizations planned for 4.x that just could not fit in this release. Our goal right now is to stabilize and ship a final release of Ext JS 4.1 as quickly as possible. We will then be hard at work to accelerate getting those additional gains delivered in subsequent releases.

h3. Other Goodies

As promised, this release is not purely about performance. We demonstrated the new Neptune theme at SenchaCon this year, and we are very pleased that a Neptune preview will be part of this release. Much to our delight, the Calendar example will be returning as well.

The list could go on with the many other improvements, but let’s dive in to some of the more exciting changes.

h4. Grid

By popular demand, we went back and investigated other solutions to the buffered scrolling and “infinite” scrolling mechanisms in Ext JS 4.0. We wanted to see if we could solve our technical problems without resorting to so-called “virtual scrolling”, and we are happy to report that, in fact, we can.

In 4.1, grids of (almost) every kind now use native scrolling. This vastly improves the user experience because things like acceleration, momentum and friction all work as well for grid as they do for any other scrolling content. Another welcome improvement is that this also means that scrolling is done by pixels and not whole rows. This is also true for “infinite” grids, even when the rows are variable height.

The only situation where virtual scrolling is still used is on the locked half of a locking grid. Since it has no scrollbar, native scrolling is not an option there.

Lastly, though not part of grid per se, metadata handling is now supported by Store.

h4. Border Layout

In the process of working on layouts, border layout in particular benefited from some internal restructuring. It has always been a very popular layout, but it has also suffered from some long-standing limitations:

* You could only have one region that is north, south, east or west. If you needed multiple south regions, you needed to use nested border layouts.
* You could not configure the layout such that an east or west region had priority over a north or south region. To achieve this, again, you needed to use nested border layouts.
* Components could not be added to the container after creation.
* Components could not be removed from the container after creation.

We are pleased to say that all of these limitations have been removed in Ext JS 4.1.

h4. XTemplate

Internally, Ext JS uses the XTemplate class for many things. It is a critically important part of the framework but was missing one important feature: it could not efficiently append to an array for a subsequent join operation. When we started work on bulk rendering, we decided that both DomHelper and XTemplate needed to collaborate on markup production by pushing their output onto a shared array.

We then discovered that the internals of XTemplate could not be surgically modified to support this, which allowed us to reconsider just how this piece needed to work. Some long-standing challenges and issues with XTemplate:

* It only supported the most basic control structures: “for” and “if”.
* The code generated from the template was somewhere between very hard and impossible to debug. As a result, errors in the template text were very difficult to track down.
* The template text was compiled at XTemplate construction time, which was undesirable because many XTemplate instances were never actually used.
* Executing the compiled code for a template was not as fast as it could be because it contained many internal function calls and string concatenations.

In 4.1, XTemplates are now compiled the first time they are used. This makes construction of an XTemplate nearly free. Further, the compiled code is now a single function that can be stepped into using the debugger, and it looks very much like the original template.

With this approach, many things became simple to support. Like “else” and “else if” statements and “switch” statements. Even literal code insertion (similar to JSP or ASP) was now a trivial extension.

var tpl = new Ext.XTemplate(
”,
‘Order {id} is ‘,
”,
‘large’,
”,
‘medium’,
”,
‘small’,
”,
‘{% continue; %}’,
”,
‘Items:’,

”);

The “<tpl for>” statement generates a proper “for” loop while the “<tpl if>”, “<tpl elseif>” and “<tpl else>” generate the obvious “if” and “else” blocks.

The new “{% x %}” syntax is used similar to “{[ x ]}”. The body of both of these is treated as arbitrary code. In the “{[ x ]}” expression, x is an expression that produces a value that is placed into the output. In the “{% x %}” case, “x” is simply inserted into the function. In this case, it will continue the for loop when reached.

h4. Overrides

In Ext JS, it has long been a common practice to share bug fixes and enhancements in the form of an “override”. In the past, these had to be manually managed as special entities. They operated on existing classes, whereas just about all other code in Ext JS 4.0 uses class names as strings. For example, to derive from Ext.panel.Panel:

Ext.define(‘My.app.Panel’, {
extend: ‘Ext.panel.Panel’,

method: function () {
this.callParent();
}
});

But to apply an override to the same Panel class (in Ext JS 4.0), the shape changes completely:

Ext.panel.Panel.override({
method: function () {
this.callOverridden(); // not possible before 4.x
}
});

And this code will fail if the Panel class is not loaded already. The inheritance use case would not fail, but would instead inform the loader/builder that Ext.panel.Panel was required.

Overrides are now first-class citizens. They can be named and loaded when needed. In fact, writing an override is just about identical to writing a derived class.

Ext.define(‘My.app.PanelPatch’, {
override: ‘Ext.panel.Panel’,

method: function () {
this.callParent();
}
});

Not only does this support the classic uses for override in a managed way, but overrides can actually become tools in your designs similar to a mixin. Where a mixin is always part of the class (like the base class), overrides can be bolted on later and only if desired or needed.

h3. Conclusion

We hope you get a chance to download and try out the new features and improvements as we approach the final release of Ext JS 4.1. We are looking forward to getting feedback from everyone on how this release has benefited you, and where we should look at further improvements.