1. #1
    Sencha User
    Join Date
    Sep 2008
    Posts
    118
    Vote Rating
    1
    RobWilson is on a distinguished road

      0  

    Default Upgrade from 4.0.2a to 4.1.1 results in massive performance hit with grids (+CSS)

    Upgrade from 4.0.2a to 4.1.1 results in massive performance hit with grids (+CSS)


    Hi,

    I had a couple of minor bugs in ExtJS that I felt might have been fixed between v4.0.2a and v4.1.1, so today I decided to download v4.1.1 and was really disappointed to see a massive reduction in performance with grids.

    Is there any known gotchas that I should have taken into account when upgrading that may have prevented this?

    Is there a way to detect where the performance issues lie? (I have tried to use the page-analyzer, but it loads with a blank page, but I can see that the analyzer has tried to load an IFrame that doesn't exist)

    Code:
    Request URL:http://localhost:8084/MySite/ux//IFrame.js?_dc=1343753401644
    Request Method:GET
    Status Code:404 Not Found
    Request Headersview source
    Accept:*/*
    Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
    Accept-Encoding:gzip,deflate,sdch
    Accept-Language:en-US,en;q=0.8
    Connection:keep-alive
    Host:localhost:8084
    Referer:http://localhost:8084/MySite/page-analyzer/page-analyzer.html
    User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11
    Query String Parametersview URL encoded
    _dc:1343753401644
    Response Headersview source
    Content-Length:1033
    Content-Type:text/html;charset=utf-8
    Date:Tue, 31 Jul 2012 16:50:01 GMT
    Server:Apache-Coyote/1.1
    Has anyone else experienced a performance reduction since upgrading?

    When I was using v4.0.2a I didn't configure my Models properly (I only defined one column, not any of the others), but magically it rendered all the data in v4.0.2a, to get it working in v4.1.1 I've had to add each property in the Model - this seems fair enough, but I was surprised it used to work at all. I hoped this was the cause of the performance problem, but it made no difference at all.

    Another problem that I've noticed is that the code that used to set the background colour of a row doesn't seem to be working (it's invoked, but doesn't take effect), a snippet:

    Code:
    ,
                    viewConfig : {
                        stripeRows: false,
                        getRowClass: function(record, index) {
                            var r = record.get("buySell");
                            if (r == "Buy") {
                                return ".grid-row-buy"; //<-- Note tried one prefixed with dot
                            } else {
                                return "grid-row-sell"; // <-- ... and one without (used to work)
                            }
                        }
                    },
    And the CSS (inline)

    Code:
            <link rel="stylesheet" href="3rdParty/extjs-4.1.1/resources/css/ext-all.css"/>
            <style type="text/css">
                .grid-row-buy {background-color : lightblue !important;}
                .grid-row-sell {background-color : #f62422 !important;}
                ...
            </style>
    Any pointers would be appreciated, particularly any changes between 4.0.2a and 4.1.1 that could explain the performance problems?

  2. #2
    Sencha User
    Join Date
    Sep 2008
    Posts
    118
    Vote Rating
    1
    RobWilson is on a distinguished road

      0  

    Default


    Quote Originally Posted by RobWilson View Post
    tried to load an IFrame that doesn't exist)
    Note that I read the article here http://www.sencha.com/blog/optimizin...-applications/ and it doesn't mention anything more than copying the page analyzer to the server and then trying to access it in the browser, I've done that part, but the error comes after loading the page-analyzer, BEFORE I get the option to type in the address of the page that I want to test.

  3. #3
    Sencha - Support Team scottmartin's Avatar
    Join Date
    Jul 2010
    Location
    Houston, Tx
    Posts
    8,882
    Vote Rating
    439
    scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future

      0  

    Default


    Are you able to put together a small test case that can be used for testing so the dev team can have a look?

    Scott.

  4. #4
    Sencha User
    Join Date
    Sep 2008
    Posts
    118
    Vote Rating
    1
    RobWilson is on a distinguished road

      0  

    Default


    Quote Originally Posted by scottmartin View Post
    Are you able to put together a small test case that can be used for testing so the dev team can have a look?

    Scott.
    Yes, although it's probably not what you would consider 'small'!

    First, a screen shot to help explain what I am trying to achieve

    Screen Shot 2012-08-01 at 17.34.08.jpg

    My observations are the following:
    • The combo performance is affected by the number of rows present in the table (IE 9 seems okay)
    • The background colour rendering of the rows does not happen when I upgrade from ExtJS4.0.2a to 4.1.1 (I wonder whether this is affecting performance?)
    • The number of rows in the grid degrades performance in Chrome slightly (version 20.0.1132.57), Safari significantly (6.0 - 8536.25), IE9 seems okay (yes I am surprised!).
    I'm running on a MacBook Pro, OS X 10.8, 8 Gig Ram, 2.7 Ghz Intel Core i7. IE9 is running through Windows 7 in a Parallels VM.

    Simply comment out the links to extJS4.0.2a and un-comment the links to extjs4.1.1 to see the performance deterioration.

    I have tried to keep the sample representative of my codebase, without passing the whole sourcecode, so there's coding styles in here that aren't as pretty as they perhaps should be, but the essence of the complexity of column types and screen layout is correct.

    Code:
                                                                    <!DOCTYPE html>
    <html>
        <head>
            <title>Grid performance test</title>
    
    
            <!-- PLEASE COMMENT OUT 'FASTER' AND UN-COMMENT 'SLOWER' 
            
            <!-- FASTER -->
            <link rel="stylesheet" href="3rdParty/extjs-4.0.2a/resources/css/ext-all.css"/>
            <script type="text/javascript" charset="utf-8" src="3rdParty/extjs-4.0.2a/ext-all.js"></script>
            
            
            <!-- SLOWER 
            <link rel="stylesheet" href="3rdParty/extjs-4.1.1/resources/css/ext-all.css"/>
            <script type="text/javascript" charset="utf-8" src="3rdParty/extjs-4.1.1/ext-all.js"></script>
            -->
    
    
            <style type="text/css">
                .grid-row-buy {background-color : lightblue !important;}
                .grid-row-sell {background-color : #f62422 !important;}
            </style>
        </head>
    
    
        <body>
            <script>
                
                Ext.onReady(function(){
                    
                    var MODEL_1_MAX = 150;
                    var MODEL_2_MAX = 250;
                    
                    /** 
                     *
                     *INITIALISE COMBO 
                     *
                     **/
                    var data = new Array();
                    for(var i=0;i<100;i++) {
                        data.push({
                            currency : "Item"+i
                        });                 
                        
                    }   
                    
                    Ext.regModel('combo1Model', {
                        fields: [
                            {type: 'string', name: 'currency'}
                        ]
                    });
    
    
                    Ext.create('Ext.data.Store', {
                        storeId: "combo1StoreId",
                        model: 'combo1Model',
                        data : data
                    });
                    
                    /**
                     *
                     *INITIALISE MAIN VIEW
                     *
                     *WEST = Data Entry Panel
                     *CENTER = Grid 1
                     *SOUTH = Grid 2
                     **/
                    var mainView = Ext.define('Example.view.ui.MainView', {
                        extend: 'Ext.panel.Panel',
    
    
                        height: 632,
                        width: 746,
                        layout: {
                            type: 'border'
                        },
    
    
                        initComponent: function() {
                            var me = this;
    
    
                            Ext.applyIf(me, {
                                items: [
                                    {
                                        xtype: 'panel',
                                        id: 'centralPanelId',
                                        layout: {
                                            type: 'border'
                                        },
                                        animCollapse: false,
                                        region: 'center',
                                        split: true,
                                        items: [
                                            {
                                                xtype: 'panel',
                                                height: 150,
                                                id: 'grid2',
                                                layout: {
                                                    type: 'fit'
                                                },
                                                collapseDirection: 'bottom',
                                                collapsible: true,
                                                title: 'SECOND GRID',
                                                flex: 1,
                                                region: 'south',
                                                split: true
                                            },
                                            {
                                                xtype: 'container',
                                                id: 'grid1',
                                                layout: {
                                                    type: 'fit'
                                                },
                                                region: 'center'
                                            }
                                        ]
                                    },
                                    {
                                        xtype: 'panel',
                                        width: 444,
                                        collapseDirection: 'left',
                                        collapsible: true,
                                        title: 'Data Entry',
                                        titleCollapse: true,
                                        region: 'west',
                                        items: [
                                            {
                                                xtype: 'panel',
                                                items: [
                                                    {
                                                        xtype: 'form',
                                                        bodyPadding: 10,
                                                        items: [
                                                            {
                                                                xtype: 'fieldset',
                                                                title: 'XXX1',
                                                                items: [
                                                                    {
                                                                        xtype: 'textfield',
                                                                        id: 'searchFieldId',
                                                                        width: 354,
                                                                        fieldLabel: 'YYY',
                                                                        anchor: '100%'
                                                                    }
                                                                ]
                                                            },
                                                            {
                                                                xtype: 'fieldset',
                                                                title: 'XXX2',
                                                                items: [
                                                                    {
                                                                        xtype: 'textfield',
                                                                        disabled: true,
                                                                        fieldLabel: 'AAAA',
                                                                        anchor: '100%'
                                                                    },
                                                                    {
                                                                        xtype: 'textfield',
                                                                        disabled: true,
                                                                        fieldLabel: 'BBB',
                                                                        anchor: '100%'
                                                                    },
                                                                    {
                                                                        xtype: 'textfield',
                                                                        disabled: true,
                                                                        fieldLabel: 'CCC',
                                                                        anchor: '100%'
                                                                    },
                                                                    {
                                                                        xtype: 'textfield',
                                                                        disabled: true,
                                                                        fieldLabel: 'DDD',
                                                                        anchor: '100%'
                                                                    }
                                                                ]
                                                            }
                                                        ]
                                                    }
                                                ]
                                            },
                                            {
                                                xtype: 'panel',
                                                id: 'OrderDetailsId',
                                                title: '',
                                                items: [
                                                    {
                                                        xtype: 'form',
                                                        bodyPadding: 10,
                                                        items: [
                                                            {
                                                                xtype: 'fieldset',
                                                                id: 'orderDetailsPanelId',
                                                                layout: {
                                                                    columns: 3,
                                                                    type: 'table'
                                                                },
                                                                title: 'SLOW!! COMBOS',
                                                                items : [
                                                                    {
                                                                        xtype: 'combobox',
                                                                        id: 'combo1Id',
                                                                        width: 230,
                                                                        fieldLabel: 'Combo 100 entries',
                                                                        //labelWidth: 142,
                                                                        store: Ext.getStore("combo1StoreId"),
                                                                        colspan: 3,
                                                                        queryMode: 'local',
                                                                        displayField:'currency',
                                                                        valueField:'currency',
                                                                        forceSelection : true,
                                                                        typeAhead : true
                                                                    }
                                                                ]
                                                            }
                                                        ]
                                                    }
                                                ]
                                            }
                                        ]
                                    }
                                ]
                            });
    
    
                            me.callParent(arguments);
                        }
                    });
    
    
                    
                    Ext.create('Ext.container.Viewport', {
                        layout : 'fit',
                        items :[
                            new mainView()
                        ]
                    }); 
                    
                        
                    Ext.define('ui.grid1', {
                        that: this,
                        id: "grid1Id",
                        extend: 'Ext.grid.Panel',
                        autoScroll : true,
                        //title: 'Order Blotter',
                        store: Ext.create('Ext.data.Store', {
                            id : 'Store1Id',
                            model : Ext.define('Model1', {
                                extend: 'Ext.data.Model',
                                fields: [
                                    {name: 'c1', type: 'string'},
                                    {name: 'c2', type: 'date'},
                                    {name: 'c3', type: 'string'},
                                    {name: 'c4', type: 'number'},
                                    {name: 'c5', type: 'number'}, 
                                    {name: 'c6', type: 'number'},
                                    {name: 'c7', type: 'string'},
                                ]
                            })
                        
                        }),
                        viewConfig : {
                            stripeRows: false,
                            getRowClass: function(record, index) {
                                var r = record.get("c7");
                                if (r == "B") {
                                    return "grid-row-buy";
                                } else {
                                    return "grid-row-sell";
                                }
                            }
                        },
                        initComponent: function() {
                            var me = this;
    
    
                            Ext.applyIf(me, {
                                columns: [
                                    {xtype: 'gridcolumn',dataIndex: 'c1',text: 'C1'},
                                    {xtype: 'datecolumn',dataIndex: 'c2',text: 'C2',format: 'd-m-y H:i:s'},
                                    {xtype: 'gridcolumn',dataIndex: 'c3',text: 'C3'},
                                    {xtype: 'numbercolumn',dataIndex: 'c4',text: 'C4'},
                                    {xtype: 'numbercolumn',dataIndex: 'c5',text: 'C5'},
                                    {xtype: 'numbercolumn',dataIndex: 'c6',text: 'C6'},                           
                                    {xtype: 'gridcolumn',dataIndex: 'c7',text: 'C7 (B/S)'}
                                ]
                            });
    
    
                            me.callParent(arguments);
                        }
                    });
     
                    Ext.getCmp("grid1").add(Ext.create('ui.grid1'));     
         
                    
                    // Populate grid 1 datastore
                    var rows = new Array();
                    var ds = Ext.getStore("Store1Id");
                    for (var i=0;i<MODEL_1_MAX;i++){
                        rows.push( Ext.create('Model1',{
                            c1 : "A",
                            c2 : new Date(),
                            c3 : "C",
                            c4 : 10+i,
                            c5 : 20+i,
                            c6 : 30+i,
                            c7 : "B"
                        }));
                    }
                    ds.add(rows);
                    
                    /*
                     * 
                     * SECOND GRID
                     */
                    Ext.define('ui.grid2', {
                        that: this,
                        id: "grid2Id",
                        extend: 'Ext.grid.GridPanel',
                        autoScroll : true,
                        store: Ext.create('Ext.data.Store', {
                            id : 'Store2Id',
    
    
                            model : Ext.define('Model2', {
                                extend: 'Ext.data.Model',
                                fields: [
                                    {name: 'c1', type: 'string'},
                                    {name: 'c2', type: 'string'},
                                    {name: 'c3', type: 'string'},
                                    {name: 'c4', type: 'string'},
                                    {name: 'c5', type: 'string'},
                                    {name: 'c6', type: 'string'},
                                    {name: 'c7', type: 'number'},
                                    {name: 'c8', type: 'number'},
                                    {name: 'c9', type: 'string'},
                                    {name: 'c10', type: 'string'},
                                    {name: 'c11', type: 'date'},
                                    {name: 'c12', type: 'number'},
                                    {name: 'c13', type: 'date' },
                                    {name: 'c14', type: 'string'}
                                ]
                            })
                        }),
                        viewConfig : {
                            stripeRows: false,
                            getRowClass: function(record, index) {
                                var r = record.get("c14");
                                if (r == "B") {
                                    return "grid-row-buy";
                                } else {
                                    return "grid-row-sell";
                                }
                            }
                        },
                        initComponent: function() {
                            var me = this;
    
    
                            Ext.applyIf(me, {
                                columns: [
                                    {xtype: 'gridcolumn',dataIndex: 'c1',text: 'C1'},
                                    {xtype: 'gridcolumn',dataIndex: 'c2',text: 'C2'},
                                    {xtype: 'gridcolumn',dataIndex: 'c3',text: 'C3'},
                                    {xtype: 'gridcolumn',dataIndex: 'c4',text: 'C4'},
                                    {xtype: 'gridcolumn',dataIndex: 'c5',text: 'C5'},
                                    {xtype: 'gridcolumn',dataIndex: 'c6',text: 'C6'},
                                    {xtype: 'numbercolumn',dataIndex: 'c7',text: 'C7'},
                                    {xtype: 'numbercolumn',dataIndex: 'c8',text: 'C8'},
                                    {xtype: 'gridcolumn',dataIndex: 'c9',text: 'C9'},
                                    {xtype: 'gridcolumn',dataIndex: 'c10',text: 'C10'},
                                    {xtype: 'datecolumn',dataIndex: 'c11',text: 'C11',format: 'd-m-y H:i:s'},
                                    {xtype: 'numbercolumn',dataIndex: 'c12',text: 'C12'},
                                    {xtype: 'gridcolumn',dataIndex: 'c13',text: 'C13' },
                                    {xtype: 'gridcolumn',dataIndex: 'c14',text: 'C14'}  
                                ]
                            });
    
    
                            me.callParent(arguments);
                        }
                    });
     
                    Ext.getCmp("grid2").add(Ext.create('ui.grid2'));
                  
                    // Populate grid 1 datastore
                    // (yes, inefficient adding - I could have an array to batch add)
                    ds = Ext.getStore("Store2Id");
                    rows = new Array();
                    for (i=0;i<MODEL_2_MAX;i++){
                        rows.push(Ext.create('Model2',{
                            c1 : "A",
                            c2 : "B",
                            c3 : "C",
                            c4 : "D",
                            c5 : "E",
                            c6 : "F",
                            c7 : 100+i,
                            c8 : 200+i,
                            c9 : "I",
                            c10 : "J",
                            c11 : new Date(),
                            c12 : 300+i,
                            c13 : new Date(),
                            c14 : "S"
    
    
                        }));
                        
                    }
                    ds.add(rows);
                });
            </script>
        </body>
    </html>
    Last edited by RobWilson; 1 Aug 2012 at 9:01 AM. Reason: minor clarification

  5. #5
    Sencha User
    Join Date
    Sep 2008
    Posts
    118
    Vote Rating
    1
    RobWilson is on a distinguished road

      0  

    Default


    I'm just wondering whether this has been looked into (have I done something silly, or has ExtJS performance decreased?).

    Thank you,
    Rob.

  6. #6
    Sencha User tobiu's Avatar
    Join Date
    May 2007
    Location
    Munich (Germany)
    Posts
    2,669
    Vote Rating
    110
    tobiu is a name known to all tobiu is a name known to all tobiu is a name known to all tobiu is a name known to all tobiu is a name known to all tobiu is a name known to all

      0  

    Default


    Hi Rob,

    I am short on time right now, so I just flew over the code and so a quite big DOM overnesting in many parts, which will affect the performance.

    Code:
                    region: 'west',
                                        items: [
                                            {
                                                xtype: 'panel',
                                                items: [
                                                    {
                                                        xtype: 'form',
                                                        bodyPadding: 10,
                                                        items: [
                                                            {
    something like this. just make the west region itself a formpanel and you can remove 2 child levels. there are other spots as well.

    i recommend to read nigels blog post on this:
    http://www.sencha.com/blog/ext-js-4-1-performance/


    best regards
    tobiu
    Best regards
    Tobias Uhlig
    __________

    S-CIRCLES Social Network Engine

  7. #7
    Sencha - Ext JS Dev Team evant's Avatar
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    16,656
    Vote Rating
    583
    evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute

      0  

    Default


    Short answer is yes, the 2 main problems:

    1) Over nesting
    a) Don't use panels if you don't need to
    b) Don't nest components inside containers unless you absolutely need to

    2) Adding items dynamically
    By adding items after the viewport is rendered, you're triggering extra layouts each time. If you must, add them all together or use a combination of suspend/resume layouts.
    Evan Trimboli
    Sencha Developer
    Twitter - @evantrimboli
    Don't be afraid of the source code!

  8. #8
    Sencha User
    Join Date
    Sep 2008
    Posts
    118
    Vote Rating
    1
    RobWilson is on a distinguished road

      0  

    Default


    Thank you for your replies regarding performance, however with no code changes between version 4.0.2 a and version 4.1.1, I wonder why 4.1.1 is significantly slower?

    I will of course take your advice, and update the code on Monday or Tuesday and provide some feedback.


    Part of my problem was creating the initial UI within EXT JS designer, it did not have all of the properties required to set things at design time, so I resorted to adding things dynamically afterwards, however this part does not seem to significantly reduce performance as it's a one off at the beginning of the application life-cycle, I'm more concerned that scrolling through grids is significantly slower in the latter release of EXT JS.

    Do you feel that the container hierarchy is also causing problems with the combo boxes? It seemed very varied between the different browsers, some seemed almost unworkable.

    Did you manage to run my example code, with version 4.0.2.A and were able compare it to 4.1.1? Is the reduction in performance what you would expect to see with nested containers? Why was this not an issue inversion 4.0.2A?

    Thank you!
    Rob.