-
31 Jul 2012 8:57 AM #1
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)
Has anyone else experienced a performance reduction since upgrading?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
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:
And the CSS (inline)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) } } },
Any pointers would be appreciated, particularly any changes between 4.0.2a and 4.1.1 that could explain the performance problems?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>
-
31 Jul 2012 9:04 AM #2
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.
-
31 Jul 2012 9:19 PM #3
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.
-
1 Aug 2012 9:00 AM #4
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!).
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
-
3 Aug 2012 8:21 AM #5
I'm just wondering whether this has been looked into (have I done something silly, or has ExtJS performance decreased?).
Thank you,
Rob.
-
3 Aug 2012 10:12 PM #6
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.
something like this. just make the west region itself a formpanel and you can remove 2 child levels. there are other spots as well.Code:region: 'west', items: [ { xtype: 'panel', items: [ { xtype: 'form', bodyPadding: 10, items: [ {
i recommend to read nigels blog post on this:
http://www.sencha.com/blog/ext-js-4-1-performance/
best regards
tobiu
-
3 Aug 2012 10:24 PM #7
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!
-
5 Aug 2012 11:57 AM #8
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.


Reply With Quote