What makes your ExtJS application run so slow ?

By “slow” here I mean the slow run-time, not the load time of resources.

In the past one year and a half, I have been working at Bosch Software Innovations, Robert Bosch, where our frontend technology stack heavily relies on ExtJS. I had chances to develop Visual Rules Web Modeler and helped with several other ExtJS-based apps  and I did experience a lot of performance issues with ExtJS apps in common.

In this article, I’m gonna share with you the key bottlenecks that might cause an ExtJS app to run slow, and also point out the mistakes that rookie ExtJS devs most likely make.

ExtJS in this article refers to the version 3.3.x and below.

1. Over-declaration of Ext.Panel

The most used ExtJS component, IMO, would be Ext.Panel. Declaring a panel with ExtJS is so simple that developers could easily over-declare them. Below is a typical declaration of a panel with nested sub-panels.

var panel = new Ext.Panel({         // Level-1
     title: 'Multi Column, Nested Layouts and Anchoring',
     bodyStyle:'padding:5px 5px 0',
     width: 600,
     items: [{                   // Level-2
        layout:'column',
        items:[{                // Level-3
               columnWidth:.5,
               layout: 'vbox',
               items: [{           // Level-4
                  html: 'This is some text'
               }, {
                  html: 'This is another text'
               }]
        },{
               columnWidth:.5,
               layout: 'form',
               items: [{
                      xtype:'textfield',
                      fieldLabel: 'Last Name',
                      name: 'last',
                      anchor:'95%'
               },{
                      xtype:'textfield',
                      fieldLabel: 'Email',
                      name: 'email',
                      vtype:'email',
                      anchor:'95%'
               }]
       }]
   }]
});

Any problem with this config ? NooO !? The problem is that this panel has four nested levels of panels, but it actually needs two in order to work and look as desired.

  • This is an example of over-declaration which leads to seriously deep nested level of HTMLElements created, and severely affects the initialization/rendering time and run time of the component.
  • I’ve seen ExtJS developers who just like to declare nested panels because it’s convenient for them to put some CSS styles, text or images inside.. or sometimes just because adding another level of panel makes the form look as desired !?!
  • The rule of thumb is: use as few panels and nested levels of components/panels as possible.

To achieve this you need to wisely make use of Ext layouts and CSS styles when declaring a complex component.

2. Delay the HTMLElement creation whenever possible

Interacting (Read/Write) with the DOM is always not cheap, especially on IE 6, reading the DOM also causes re-flow.

So the rule of thumb is: try to delay the creation of HTMLElements whenever possible. This could be achieved by:

  • Component Lazy instantiation. This is possible with xtype.
  • Try to defer expensive operations till afterrender.
  • Avoid unnecessarily instantiating/rendering components in the constructor or initComponent of another component.

Example 1: A simple example is do not create Ext.Tooltip and render it hiddenly in the DOM when the button is first rendered. The tooltip usually should be rendered at the first time users hover mouse over the button. If tooltip is rendered right after the button, and users never hover mouse over the button. We have already created a wasted, never-used tooltip which adds up to the performance issue.

Example 2: Another example is careless use of renderTo:

var window = new Ext.Window({
     renderTo: document.body,
     title: 'The Untitled'
});

window.show(); // the window has been rendered before this line

With the above declaration, the window will be rendered immediately and hidden to the <body> tag. In many cases, we don’t need the renderTo,  the window should be rendered only when it is displayed the first time as following:

var window = new Ext.Window({
       title: 'The Untitled'
});

window.show(); // the window is to be rendered and displayed at this line

3. Use the delegate pattern whenever possible:

I’m not gonna dig into the details of delegate pattern here, but will rephrase it in ExtJS language instead.

Example: An example of delegate pattern is that you have an Ext.Toolbar with 10 Ext.Button, and you need to assign Ext.Tooltip to every button so that when users hover mouse over a button, a Tooltip is displayed with an explanation text.

If you create 10 Ext.Tooltip and assign them to 10 Ext.Button then it is not the most optimized solution. You can create only 1 Ext.Tooltip and assign it to the parent element, which is Ext.Toolbar, of those 10 Ext.Button.

When users hover mouse over the Ext.Toolbar, you will display the same Ext.Tooltip but with different explanation text according to the target element ( actual Ext.Button ) being mouse over. (See getTarget for how to get target element)

With this technique, only 1 Ext.Tooltip is created, and 1 event listener is attached to the Ext.Toolbar.

  • Saves you a lot of memory usage and run time of your app but still achieves the same result.

You might want to look at delegate config property of Ext.Tooltip for the sample implementation.

4. Component destruction – How to destroy things properly

This is one of the main bottlenecks I found in the slow ExtJS apps that I have helped improving the performance. The idea is when a component is not in use any more, we should clean up :

  • The HTMLElements existing in the DOM
  • Dettach all event listeners to avoid memory leaks.
  • Destroy all descendant components in the same recursive way

These above are handled in the method destroy of an Ext.Component. There are cases you need to call #destroy method during run time as leaving unused components in the DOM would lead to severe slow performance.

Example 1: if you happen to create a custom Context Menu (Ext.menu.Menu) inside a panel (Ext.Panel), remember to override the destroy method of the panel, and destroy the context menu in there. Later if the panel gets destroyed, your context menu gets destroyed too.

Your.Component.Klass = Ext.extend(Ext.Component, {
initComponent: function(){
     // Initialize your custom stuff
     this.contextMenu = new Ext.menu.Menu({
           renderTo: document.body
           // ..
      });
},

destroy: function(){
      // Destroy your custom stuff
      this.contextMenu.destroy();
      this.contextMenu = null;

      // Destroy the component
      Your.Component.Klass.superclass.destroy.call(this);
}
});

Example 2: One common mistake is the misuse of config option closeAction of Ext.Window.

If you configure closeAction as ‘hide‘, the window will be hidden when users hit the ‘Close’ button. However, there is a chance that, the window will never be displayed again through out the whole run time. So make sure if yosu really want to do the show/hide, otherwise always configure closeAction as ‘close‘ for the .destroy method will be called on the window after it is hidden to destroy it properly.

var window = new Ext.Window({
   closeAction: 'hide',
   title: 'The Untitled'
});

window.show(); // render and display the window
window.hide(); // the window is not destroyed but only hidden in the DOM.

I hope this article would give you some clues fighting with performance issues of your ExtJS-based applications. If you have other experience regarding performance issues specific to ExtJS apps, feel free to share here ! :D

Cheers,

Totti

, , ,

  • momochi

    Thanks for sharing the tips, Totti. We’re trying to improve the perf of our ExtJS app and definitely need to take care of the stated issues.

  • Interessanter Artikel und gut geschrieben.

  • sajid ali

    Thank you for providing helpful information, but it would be very helpful if you had provided some detailed or even simple examples of the solutions you have suggested.

  • Pingback: » 是什么让你的ExtJS应用程序运行缓慢?zend实验室-java/php学习教程,web前端设计,编程开发经验,代码分享,网站运营推广()

  • Slava Nadvorny

    It’s actually not the nesting problem issue, but rather ExtJS architecture issue. Instead of relying on super-fast-optimized native browser layout mechanism it uses not-so-optimal custom layout mechanism.

    To prove it simply compare it with GWT, where layout works almost instantly for virtually any nesting level.

    • Thanks for your comment.
      I agree with you that ExtJS architecture should provide different optimized layout mechanisms for different lines of browsers. As there is no one solution that works best for all browsers.
      Definitely we can’t compare the native browser layout of Chrome vs IE 6.
      So I just try to point out what to avoid in ExtJS instead :)

      • Piyush Dholariya

        Good totti,
        currently we have one ExtJS application & we want to do css performance improvement so can you give any suggestion for that?

        • CSS optimization is at the micro-level optimization.

          So my thought is if you follow general CSS tips such as avoiding “expression” if possible, using sprites, using gzip, and CDN, etc., then you should be fine. There is not much to wiggle around the in CSS part of ExtJS.

  • Venkatesh Teja

    Thanks Totti,

    You provided help full information. Through this we can avoid
    atleast minimum memory leakage.

    • Thanks for coming by! And good luck with your ExtJS dev :)

  • Sneha

    Brilliant! Very Helpful :) Thanks

  • Harshal

    Really!! Interesting inputs to make ExtJS website light and faster…even this tips could be helpful for non-extjs coding too. We should take care of dom elements rendering with any Javascript Framework. Unnecessary elements can cause a performance issue to your website.

    • Albert mckansy

      Really !!!!!!!!!!! you are like fraud person.