@Skirtle,
I've gone back back and recoded and re tested using the Sencha EXTJS Page Analyser and I can now see the deferredRender working correctly.
Thanks again! :)
Printable View
@Skirtle,
I've gone back back and recoded and re tested using the Sencha EXTJS Page Analyser and I can now see the deferredRender working correctly.
Thanks again! :)
@MrSparks will you now be able to compare the revised v4.1 example against the v3.4 performance and update the benchmark?
Thanks!
@MrSparks - do you happen to have some results in the meanwhile? Thanks! I'm also interested. We are also having big problems with the performance.
@MrSparks. I've optimized your test case a little. Pretty much all of my optimizations are lazy instantiation - only creating components when they're needed.
IE 6:
6.0s => 2.5s
IE 8:
2.9s => 1.1s
I'd be curious to see what difference it makes for you.
Code:<html>
<head>
<title>Simple App EXTJS 4.1.1</title>
<script type="text/javascript">
var start = new Date().getTime();
</script>
<link rel="stylesheet" type="text/css" href="lib/extjs/4.1.1/resources/css/ext-all.css" />
<style type="text/css">
p {
margin:5px;
}
.settings {
background-image:url(lib/extjs/4.1.1/examples/shared/icons/fam/folder_wrench.png);
}
.nav {
background-image:url(lib/extjs/4.1.1/examples/shared/icons/fam/folder_go.png);
}
.info {
background-image:url(lib/extjs/4.1.1/examples/shared/icons/fam/information.png);
}
</style>
<script type="text/javascript" src="lib/extjs/4.1.1/ext-all.js"></script>
<script type="text/javascript" src="lib/extjs/4.1.1/examples/shared/states.js"></script>
<script type="text/javascript">
/********
* Data *
********/
var myData = [
['3m Co', 71.72, 0.02, 0.03, '9/1 12:00am'],
['Alcoa Inc', 29.01, 0.42, 1.47, '9/1 12:00am'],
['Altria Group Inc', 83.81, 0.28, 0.34, '9/1 12:00am'],
['American Express Company', 52.55, 0.01, 0.02, '9/1 12:00am'],
['American International Group, Inc.', 64.13, 0.31, 0.49, '9/1 12:00am'],
['AT&T Inc.', 31.61, -0.48, -1.54, '9/1 12:00am'],
['Boeing Co.', 75.43, 0.53, 0.71, '9/1 12:00am'],
['Caterpillar Inc.', 67.27, 0.92, 1.39, '9/1 12:00am'],
['Citigroup, Inc.', 49.37, 0.02, 0.04, '9/1 12:00am'],
['E.I. du Pont de Nemours and Company', 40.48, 0.51, 1.28, '9/1 12:00am'],
['Exxon Mobil Corp', 68.1, -0.43, -0.64, '9/1 12:00am'],
['General Electric Company', 34.14, -0.08, -0.23, '9/1 12:00am'],
['General Motors Corporation', 30.27, 1.09, 3.74, '9/1 12:00am'],
['Hewlett-Packard Co.', 36.53, -0.03, -0.08, '9/1 12:00am'],
['Honeywell Intl Inc', 38.77, 0.05, 0.13, '9/1 12:00am'],
['Intel Corporation', 19.88, 0.31, 1.58, '9/1 12:00am'],
['International Business Machines', 81.41, 0.44, 0.54, '9/1 12:00am'],
['Johnson & Johnson', 64.72, 0.06, 0.09, '9/1 12:00am'],
['JP Morgan & Chase & Co', 45.73, 0.07, 0.15, '9/1 12:00am'],
['McDonald\'s Corporation', 36.76, 0.86, 2.40, '9/1 12:00am'],
['Merck & Co., Inc.', 40.96, 0.41, 1.01, '9/1 12:00am'],
['Microsoft Corporation', 25.84, 0.14, 0.54, '9/1 12:00am'],
['Pfizer Inc', 27.96, 0.4, 1.45, '9/1 12:00am'],
['The Coca-Cola Company', 45.07, 0.26, 0.58, '9/1 12:00am'],
['The Home Depot, Inc.', 34.64, 0.35, 1.02, '9/1 12:00am'],
['The Procter & Gamble Company', 61.91, 0.01, 0.02, '9/1 12:00am'],
['United Technologies Corporation', 63.26, 0.55, 0.88, '9/1 12:00am'],
['Verizon Communications', 35.57, 0.39, 1.11, '9/1 12:00am'],
['Wal-Mart Stores, Inc.', 45.45, 0.73, 1.63, '9/1 12:00am']
];
/**********
* Models *
**********/
Ext.define('Book1',{
extend: 'Ext.data.Model',
fields: [
// set up the fields mapping into the xml doc
// The first needs mapping, the others are very basic
{name: 'Author', mapping: 'ItemAttributes > Author'},
'Title', 'Manufacturer', 'ProductGroup'
]
});
Ext.define('Book2',{
extend: 'Ext.data.Model',
fields: [
// set up the fields mapping into the xml doc
// The first needs mapping, the others are very basic
{name: 'Author', mapping: 'ItemAttributes > Author'},
'Title', 'Manufacturer', 'ProductGroup'
]
});
Ext.define('Book3',{
extend: 'Ext.data.Model',
fields: [
// set up the fields mapping into the xml doc
// The first needs mapping, the others are very basic
{name: 'Author', mapping: 'ItemAttributes > Author'},
'Title', 'Manufacturer', 'ProductGroup'
]
});
Ext.define('Book4',{
extend: 'Ext.data.Model',
fields: [
// set up the fields mapping into the xml doc
// The first needs mapping, the others are very basic
{name: 'Author', mapping: 'ItemAttributes > Author'},
'Title', 'Manufacturer', 'ProductGroup'
]
});
Ext.define('example.contact1', {
extend: 'Ext.data.Model',
fields: [
{name: 'first', mapping: 'name > first'},
{name: 'last', mapping: 'name > last'},
'company', 'email', 'state',
{name: 'dob', type: 'date', dateFormat: 'm/d/Y'}
]
});
Ext.define('example.fielderror1', {
extend: 'Ext.data.Model',
fields: ['id', 'msg']
});
Ext.define('example.contact2', {
extend: 'Ext.data.Model',
fields: [
{name: 'first', mapping: 'name > first'},
{name: 'last', mapping: 'name > last'},
'company', 'email', 'state',
{name: 'dob', type: 'date', dateFormat: 'm/d/Y'}
]
});
Ext.define('example.fielderror2', {
extend: 'Ext.data.Model',
fields: ['id', 'msg']
});
/**********
* Stores *
**********/
var store1 = Ext.create('Ext.data.Store', {
autoLoad: true,
model: 'Book1',
proxy: {
// load using HTTP
type: 'ajax',
url: 'lib/extjs/4.1.1/examples/grid/sheldon.xml',
// the return will be XML, so lets set up a reader
reader: {
idProperty: 'ASIN',
// records will have an 'Item' tag
record: 'Item',
totalRecords: '@total',
type: 'xml'
}
}
});
var store2 = Ext.create('Ext.data.Store', {
model: 'Book2',
autoLoad: true,
proxy: {
// load using HTTP
type: 'ajax',
url: 'lib/extjs/4.1.1/examples/grid/sheldon.xml',
// the return will be XML, so lets set up a reader
reader: {
type: 'xml',
// records will have an 'Item' tag
record: 'Item',
idProperty: 'ASIN',
totalRecords: '@total'
}
}
});
var store3 = Ext.create('Ext.data.Store', {
autoLoad: true,
model: 'Book3',
proxy: {
// load using HTTP
type: 'ajax',
url: 'lib/extjs/4.1.1/examples/grid/sheldon.xml',
// the return will be XML, so lets set up a reader
reader: {
idProperty: 'ASIN',
// records will have an 'Item' tag
record: 'Item',
totalRecords: '@total',
type: 'xml'
}
}
});
// create the Data Store
var store4 = Ext.create('Ext.data.Store', {
autoLoad: true,
model: 'Book4',
proxy: {
// load using HTTP
type: 'ajax',
url: 'lib/extjs/4.1.1/examples/grid/sheldon.xml',
// the return will be XML, so lets set up a reader
reader: {
idProperty: 'ASIN',
// records will have an 'Item' tag
record: 'Item',
totalRecords: '@total',
type: 'xml'
}
}
});
var tstore1 = Ext.create('Ext.data.TreeStore', {
proxy: {
type: 'ajax',
url: 'lib/extjs/4.1.1/examples/tree/check-nodes.json'
},
sorters: [
{
direction: 'ASC',
property: 'leaf'
}, {
direction: 'ASC',
property: 'text'
}
]
});
var tstore2 = Ext.create('Ext.data.TreeStore', {
proxy: {
type: 'ajax',
url: 'lib/extjs/4.1.1/examples/tree/check-nodes.json'
},
sorters: [
{
direction: 'ASC',
property: 'leaf'
}, {
direction: 'ASC',
property: 'text'
}
]
});
var tstore3 = Ext.create('Ext.data.TreeStore', {
proxy: {
type: 'ajax',
url: 'lib/extjs/4.1.1/examples/tree/check-nodes.json'
},
sorters: [
{
direction: 'ASC',
property: 'leaf'
}, {
direction: 'ASC',
property: 'text'
}
]
});
var tstore4 = Ext.create('Ext.data.TreeStore', {
proxy: {
type: 'ajax',
url: 'lib/extjs/4.1.1/examples/tree/check-nodes.json'
},
sorters: [
{
direction: 'ASC',
property: 'leaf'
}, {
direction: 'ASC',
property: 'text'
}
]
});
var tstore5 = Ext.create('Ext.data.TreeStore', {
proxy: {
type: 'ajax',
url: 'lib/extjs/4.1.1/examples/tree/check-nodes.json'
},
sorters: [
{
direction: 'ASC',
property: 'leaf'
}, {
direction: 'ASC',
property: 'text'
}
]
});
var ds = Ext.create('Ext.data.ArrayStore', {
data: myData,
fields: [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'},
// Rating dependent upon performance 0 = best, 2 = worst
{name: 'rating', type: 'int', convert: function(value, record) {
var pct = record.get('pctChange');
if (pct < 0) {
return 2
}
if (pct < 1) {
return 1
}
return 0;
}}
]
});
/**************
* Components *
**************/
Ext.define('CardButton', {
alias: 'widget.card-button',
extend: 'Ext.button.Button',
scale: 'medium',
width: 100,
handler: function() {
var cardType = this.cardType,
card = cardPanel.child(cardType);
if (!card) {
card = cardPanel.add({xtype: cardType});
}
cardPanel.getLayout().setActiveItem(card);
}
});
Ext.define('Tree1', {
alias: 'widget.tree1',
extend: 'Ext.tree.Panel',
frame: true,
height: 250,
rootVisible: false,
store: tstore1,
title: 'Check Tree',
useArrows: true,
width: 200,
dockedItems: [{
xtype: 'toolbar',
items: {
text: 'Get checked nodes',
handler: function(){
var records = this.up('tree1').getView().getChecked(),
names = [];
Ext.Array.each(records, function(rec){
names.push(rec.get('text'));
});
Ext.MessageBox.show({
icon: Ext.MessageBox.INFO,
msg: names.join('<br />'),
title: 'Selected Nodes'
});
}
}
}]
});
Ext.define('Tree2', {
alias: 'widget.tree2',
extend: 'Ext.tree.Panel',
frame: true,
height: 250,
rootVisible: false,
store: tstore2,
title: 'Check Tree',
useArrows: true,
width: 200,
dockedItems: [{
xtype: 'toolbar',
items: {
text: 'Get checked nodes',
handler: function(){
var records = this.up('tree2').getView().getChecked(),
names = [];
Ext.Array.each(records, function(rec){
names.push(rec.get('text'));
});
Ext.MessageBox.show({
icon: Ext.MessageBox.INFO,
msg: names.join('<br />'),
title: 'Selected Nodes'
});
}
}
}]
});
Ext.define('Tree3', {
alias: 'widget.tree3',
extend: 'Ext.tree.Panel',
frame: true,
height: 250,
rootVisible: false,
store: tstore3,
title: 'Check Tree',
useArrows: true,
width: 200,
dockedItems: [{
xtype: 'toolbar',
items: {
text: 'Get checked nodes',
handler: function(){
var records = this.up('tree3').getView().getChecked(),
names = [];
Ext.Array.each(records, function(rec){
names.push(rec.get('text'));
});
Ext.MessageBox.show({
icon: Ext.MessageBox.INFO,
msg: names.join('<br />'),
title: 'Selected Nodes'
});
}
}
}]
});
Ext.define('Tree4', {
alias: 'widget.tree4',
extend: 'Ext.tree.Panel',
frame: true,
height: 250,
rootVisible: false,
store: tstore4,
title: 'Check Tree',
useArrows: true,
width: 200,
dockedItems: [{
xtype: 'toolbar',
items: {
text: 'Get checked nodes',
handler: function(){
var records = this.up('tree4').getView().getChecked(),
names = [];
Ext.Array.each(records, function(rec){
names.push(rec.get('text'));
});
Ext.MessageBox.show({
icon: Ext.MessageBox.INFO,
msg: names.join('<br />'),
title: 'Selected Nodes'
});
}
}
}]
});
Ext.define('Tree5', {
alias: 'widget.tree5',
extend: 'Ext.tree.Panel',
frame: true,
height: 250,
rootVisible: false,
store: tstore5,
title: 'Check Tree',
useArrows: true,
width: 200,
dockedItems: [{
xtype: 'toolbar',
items: {
text: 'Get checked nodes',
handler: function(){
var records = this.up('tree5').getView().getChecked(),
names = [];
Ext.Array.each(records, function(rec){
names.push(rec.get('text'));
});
Ext.MessageBox.show({
icon: Ext.MessageBox.INFO,
msg: names.join('<br />'),
title: 'Selected Nodes'
});
}
}
}]
});
Ext.define('Grid1', {
alias: 'widget.grid1',
extend: 'Ext.grid.Panel',
height: 500,
store: store1,
columns: [
{text: 'Author', flex: 1, dataIndex: 'Author', sortable: true},
{text: 'Title', width: 180, dataIndex: 'Title', sortable: true},
{text: 'Manufacturer', width: 115, dataIndex: 'Manufacturer', sortable: true},
{text: 'Product Group', width: 100, dataIndex: 'ProductGroup', sortable: true}
]
});
Ext.define('Grid2', {
alias: 'widget.grid2',
extend: 'Ext.grid.Panel',
height: 500,
store: store2,
columns: [
{text: 'Author', flex: 1, dataIndex: 'Author', sortable: true},
{text: 'Title', width: 180, dataIndex: 'Title', sortable: true},
{text: 'Manufacturer', width: 115, dataIndex: 'Manufacturer', sortable: true},
{text: 'Product Group', width: 100, dataIndex: 'ProductGroup', sortable: true}
]
});
Ext.define('Grid3', {
alias: 'widget.grid3',
extend: 'Ext.grid.Panel',
height: 500,
store: store3,
columns: [
{text: 'Author', flex: 1, dataIndex: 'Author', sortable: true},
{text: 'Title', width: 180, dataIndex: 'Title', sortable: true},
{text: 'Manufacturer', width: 115, dataIndex: 'Manufacturer', sortable: true},
{text: 'Product Group', width: 100, dataIndex: 'ProductGroup', sortable: true}
]
});
Ext.define('Grid4', {
alias: 'widget.grid4',
extend: 'Ext.grid.Panel',
height: 500,
store: store4,
columns: [
{text: 'Author', flex: 1, dataIndex: 'Author', sortable: true},
{text: 'Title', width: 180, dataIndex: 'Title', sortable: true},
{text: 'Manufacturer', width: 115, dataIndex: 'Manufacturer', sortable: true},
{text: 'Product Group', width: 100, dataIndex: 'ProductGroup', sortable: true}
]
});
Ext.define('GridForm', {
alias: 'widget.grid-form',
extend: 'Ext.form.Panel',
bodyPadding: 5,
frame: true,
id: 'company-form',
title: 'Company data',
width: 750,
layout: 'column',
fieldDefaults: {
labelAlign: 'left',
msgTarget: 'side'
},
items: [
{
columnWidth: 0.6,
height: 400,
store: ds,
title:'Company Data',
xtype: 'gridpanel',
columns: [
{
dataIndex: 'company',
flex: 1,
id: 'company',
sortable: true,
text: 'Company'
}, {
dataIndex: 'price',
width: 75,
sortable: true,
text: 'Price'
}, {
dataIndex: 'change',
sortable: true,
text: 'Change',
width: 75,
renderer: function(val){
if (val > 0) {
return '<span style="color:green;">' + val + '</span>';
}
else if(val < 0) {
return '<span style="color:red;">' + val + '</span>';
}
return val;
}
}, {
dataIndex: 'pctChange',
sortable: true,
text: '% Change',
width: 75,
renderer: function(val){
if (val > 0) {
return '<span style="color:green;">' + val + '%</span>';
}
else if (val < 0) {
return '<span style="color:red;">' + val + '%</span>';
}
return val;
}
}, {
dataIndex: 'lastChange',
renderer: Ext.util.Format.dateRenderer('m/d/Y'),
sortable: true,
text: 'Last Updated',
width: 85
}, {
dataIndex: 'rating',
sortable: true,
text: 'Rating',
width: 30,
renderer: function(v) {
return ['A', 'B', 'C'][v];
}
}
],
listeners: {
selectionchange: function(model, records) {
if (records[0]) {
this.up('form').getForm().loadRecord(records[0]);
}
}
}
}, {
columnWidth: 0.4,
defaultType: 'textfield',
margin: '0 0 0 10',
title: 'Company details',
xtype: 'fieldset',
defaults: {
labelWidth: 90,
width: 240
},
items: [
{
fieldLabel: 'Name',
name: 'company'
}, {
fieldLabel: 'Price',
name: 'price'
}, {
fieldLabel: '% Change',
name: 'pctChange'
}, {
fieldLabel: 'Last Updated',
name: 'lastChange',
xtype: 'datefield'
}, {
columns: 3,
fieldLabel: 'Rating',
xtype: 'radiogroup',
defaults: {
name: 'rating' //Each radio has the same name so the browser will make sure only one is checked at once
},
items: [
{
boxLabel: 'A',
inputValue: '0'
}, {
boxLabel: 'B',
inputValue: '1'
}, {
boxLabel: 'C',
inputValue: '2'
}
]
}
]
}
]
});
Ext.define('FormPanel1', {
alias: 'widget.formpanel1',
extend: 'Ext.form.Panel',
bodyPadding: 5,
frame: true,
title:'XML Form',
waitMsgTarget: true,
width: 340,
fieldDefaults: {
labelAlign: 'right',
labelWidth: 85,
msgTarget: 'side'
},
// configure how to read the XML data
reader: {
model: 'example.contact1',
record : 'contact',
successProperty: '@success',
type: 'xml'
},
// configure how to read the XML errors
errorReader: {
model: 'example.fielderror1',
record: 'field',
successProperty: '@success',
type: 'xml'
},
items: [{
xtype: 'fieldset',
title: 'Contact Information',
defaultType: 'textfield',
defaults: {
width: 280
},
items: [
{
emptyText: 'First Name',
fieldLabel: 'First Name',
name: 'first'
}, {
emptyText: 'Last Name',
fieldLabel: 'Last Name',
name: 'last'
}, {
fieldLabel: 'Company',
name: 'company'
}, {
fieldLabel: 'Email',
name: 'email',
vtype:'email'
}, {
displayField: 'state',
emptyText: 'Select a state...',
fieldLabel: 'State',
name: 'state',
queryMode: 'local',
typeAhead: true,
valueField: 'abbr',
xtype: 'combobox',
store: Ext.create('Ext.data.ArrayStore', {
data : Ext.example.states, // from states.js
fields: ['abbr', 'state']
})
}, {
allowBlank: false,
fieldLabel: 'Date of Birth',
maxValue: new Date(),
name: 'dob',
xtype: 'datefield'
}
]
}],
buttons: [
{
text: 'Load',
handler: function(){
this.up('form').getForm().load({
url: 'lib/extjs/4.1.1/examples/form/xml-form-data.xml',
waitMsg: 'Loading...'
});
}
}, {
disabled: true,
formBind: true,
text: 'Submit',
handler: function(){
this.up('form').getForm().submit({
submitEmptyText: false,
url: 'xml-form-errors.xml',
waitMsg: 'Saving Data...'
});
}
}
]
});
Ext.define('FormPanel2', {
alias: 'widget.formpanel2',
extend: 'Ext.form.Panel',
bodyPadding: 5,
frame: true,
title: 'XML Form',
waitMsgTarget: true,
width: 340,
fieldDefaults: {
labelAlign: 'right',
labelWidth: 85,
msgTarget: 'side'
},
// configure how to read the XML data
reader: {
record : 'contact',
model: 'example.contact2',
successProperty: '@success',
type: 'xml'
},
// configure how to read the XML errors
errorReader: {
model: 'example.fielderror2',
record: 'field',
successProperty: '@success',
type: 'xml'
},
items: [{
xtype: 'fieldset',
title: 'Contact Information',
defaultType: 'textfield',
defaults: {
width: 280
},
items: [
{
fieldLabel: 'First Name',
emptyText: 'First Name',
name: 'first'
}, {
fieldLabel: 'Last Name',
emptyText: 'Last Name',
name: 'last'
}, {
fieldLabel: 'Company',
name: 'company'
}, {
fieldLabel: 'Email',
name: 'email',
vtype:'email'
}, {
displayField: 'state',
emptyText: 'Select a state...',
fieldLabel: 'State',
name: 'state',
queryMode: 'local',
typeAhead: true,
valueField: 'abbr',
xtype: 'combobox',
store: Ext.create('Ext.data.ArrayStore', {
data : Ext.example.states, // from states.js
fields: ['abbr', 'state']
})
}, {
allowBlank: false,
fieldLabel: 'Date of Birth',
name: 'dob',
maxValue: new Date(),
xtype: 'datefield'
}
]
}],
buttons: [{
text: 'Load',
handler: function(){
this.up('form').getForm().load({
url: 'lib/extjs/4.1.1/examples/form/xml-form-data.xml',
waitMsg: 'Loading...'
});
}
}, {
disabled: true,
formBind: true,
text: 'Submit',
handler: function(){
this.up('form').getForm().submit({
submitEmptyText: false,
url: 'xml-form-errors.xml',
waitMsg: 'Saving Data...'
});
}
}]
});
Ext.define('LazyContainer', {
alias: 'widget.lazy-container',
extend: 'Ext.container.Container',
initComponent: function() {
var me = this;
me.lazyItems = me.items;
me.items = null;
me.callParent();
},
beforeRender: function() {
var me = this,
items = me.lazyItems;
if (items) {
me.add(items);
}
me.callParent();
}
});
Ext.define('LazyPanel', {
alias: 'widget.lazy-panel',
extend: 'Ext.panel.Panel',
initComponent: function() {
var me = this,
lazyItems = me.lazyItems = me.items;
me.items = null;
me.callParent();
if (lazyItems) {
me.on('beforeexpand', me.createChildComponents, me, {single: true});
}
},
createChildComponents: function() {
this.add(this.lazyItems);
}
});
Ext.define('TabPanel1', {
alias: 'widget.tabpanel1',
extend: 'Ext.tab.Panel',
items: [
{
autoScroll: true,
closable: true,
items:[{xtype: 'grid-form'}],
title: 'Close Me',
xtype: 'lazy-container'
}, {
autoScroll: true,
items:[{xtype: 'grid1'}],
title: 'Center Panel 1',
xtype: 'lazy-container'
}, {
autoScroll: true,
items:[{xtype: 'formpanel1'}],
title: 'Center Panel 2',
xtype: 'lazy-container'
}, {
autoScroll: true,
items:[{xtype: 'grid2'}],
title: 'Center Panel 3',
xtype: 'lazy-container'
}, {
autoScroll: true,
items:[{xtype: 'grid3'}],
title: 'Center Panel 4',
xtype: 'lazy-container'
}, {
autoScroll: true,
items:[{xtype: 'grid4'}],
title: 'Center Panel 5',
xtype: 'lazy-container'
}, {
autoScroll: true,
items:[{xtype: 'formpanel2'}],
title: 'Center Panel 6',
xtype: 'lazy-container'
}, {
autoScroll: true,
title: 'Center Panel 7',
xtype: 'lazy-container',
items:[{
contentEl: 'center7'
}]
}
]
});
Ext.define('TabPanel2', {
alias: 'widget.tabpanel2',
extend: 'Ext.tab.Panel',
items: [
{
autoScroll: true,
closable: true,
html: 'Panel 2',
layout: 'border',
title: 'Close Me',
items:[
{
region: 'north',
html: 'north'
}, {
html: 'center p 2',
region: 'center',
title: 'test'
}, {
region: 'south',
html: 'south'
}
]
}, {
autoScroll: true,
title: 'Center Panel 1',
items: [
{
html: 'north',
region: 'north'
}, {
html: 'center',
region: 'center',
title: 'test'
}, {
html: 'south',
region: 'south'
}
]
}, {
autoScroll: true,
title: 'Center Panel 2',
items:[
{
html: 'north',
region: 'north',
xtype: 'panel'
}, {
html: 'center',
region: 'center',
title: 'test',
xtype: 'panel'
}, {
html: 'south',
region: 'south',
xtype: 'panel'
}
]
}, {
autoScroll: true,
title: 'Center Panel 3',
items:[
{
html: 'north',
region: 'north'
}, {
html: 'center',
region: 'center',
title: 'test'
}, {
html: 'south',
region: 'south'
}
]
}, {
autoScroll: true,
title: 'Center Panel 4',
items:[
{
html: 'north',
region: 'north'
}, {
title: 'test',
region: 'center',
html: 'center'
}, {
region: 'south',
html: 'south'
}
]
}, {
autoScroll: true,
title: 'Center Panel 5',
items:[
{
html: 'north',
region: 'north'
}, {
html: 'center',
region: 'center',
title: 'test'
}, {
html: 'south',
region: 'south'
}
]
}, {
autoScroll: true,
title: 'Center Panel 6',
items:[
{
html: 'north',
region: 'north'
}, {
html: 'center',
region: 'center',
title: 'test'
}, {
html: 'south',
region: 'south'
}
]
}, {
autoScroll: true,
title: 'Center Panel 7',
items:[
{
html: 'north',
region: 'north'
}, {
html: 'center',
region: 'center',
title: 'test'
}, {
html: 'south',
region: 'south'
}
]
}
]
});
Ext.define('TabPanel3', {
alias: 'widget.tabpanel3',
extend: 'Ext.tab.Panel',
items: [
{
autoScroll: true,
closable: true,
html: 'Panel 3',
title: 'Close Me',
items:[
{
html: 'north',
region: 'north'
}, {
html: 'center p 3',
region: 'center',
title: 'test'
}, {
html: 'south',
region: 'south'
}
]
}, {
autoScroll: true,
title: 'Center Panel 1',
items:[
{
html: 'north',
region: 'north'
}, {
html: 'center',
region: 'center',
title: 'test'
}, {
html: 'south',
region: 'south'
}
]
}, {
autoScroll: true,
title: 'Center Panel 2',
items:[
{
html: 'north',
region: 'north'
}, {
html: 'center',
region: 'center',
title: 'test'
}, {
html: 'south',
region: 'south'
}
]
}, {
autoScroll: true,
title: 'Center Panel 3',
items:[
{
region: 'north',
html: 'north'
}, {
title: 'test',
region: 'center',
html: 'center'
}, {
region: 'south',
html: 'south'
}
]
}, {
autoScroll: true,
title: 'Center Panel 4',
items:[
{
region: 'north',
html: 'north'
}, {
title: 'test',
region: 'center',
html: 'center'
}, {
region: 'south',
html: 'south'
}
]
}, {
autoScroll: true,
title: 'Center Panel 5',
items:[
{
region: 'north',
html: 'north'
}, {
title: 'test',
region: 'center',
html: 'center'
}, {
region: 'south',
html: 'south'
}
]
}, {
autoScroll: true,
title: 'Center Panel 6',
items:[
{
region: 'north',
html: 'north'
}, {
title: 'test',
region: 'center',
html: 'center'
}, {
region: 'south',
html: 'south'
}
]
},
{
autoScroll: true,
title: 'Center Panel 7',
items:[
{
region: 'north',
html: 'north'
}, {
title: 'test',
region: 'center',
html: 'center'
}, {
region: 'south',
html: 'south'
}
]
}
]
});
Ext.define('TabPanel4', {
alias: 'widget.tabpanel4',
extend: 'Ext.tab.Panel',
items: [
{
title: 'Close Me',
closable: true,
html: 'Panel 4',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center p 4'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
}, {
title: 'Center Panel 1',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 2',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 3',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 4',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 5',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 6',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 7',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
}
]
});
Ext.define('TabPanel5', {
alias: 'widget.tabpanel5',
extend: 'Ext.tab.Panel',
items: [
{
title: 'Close Me',
closable: true,
html: 'Panel 5',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center p 5'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 1',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 2',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 3',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 4',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 5',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 6',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 7',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
}
]
});
Ext.define('TabPanel6', {
alias: 'widget.tabpanel6',
extend: 'Ext.tab.Panel',
items: [
{
title: 'Close Me',
closable: true,
html: 'Panel 6',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center p 6'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 1',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 2',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 3',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 4',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 5',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 6',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 7',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
}
]
});
Ext.define('TabPanel7', {
alias: 'widget.tabpanel7',
extend: 'Ext.tab.Panel',
items: [
{
title: 'Close Me',
closable: true,
html: 'Panel 7',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center p 7'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 1',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 2',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 3',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 4',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 5',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 6',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
},
{
title: 'Center Panel 7',
autoScroll: true,
items:[
{
xtype: 'panel',
region: 'north',
html: 'north'
},
{
xtype: 'panel',
title: 'test',
region: 'center',
html: 'center'
},
{
xtype: 'panel',
region: 'south',
html: 'south'
}
]
}
]
});
Ext.onReady(function() {
Ext.QuickTips.init();
Ext.state.Manager.setProvider(Ext.create('Ext.state.CookieProvider'));
Ext.BLANK_IMAGE_URL = 'lib/extjs/4.1.1/resources/themes/images/default/tree/s.gif';
var northTb = Ext.create('Ext.toolbar.Toolbar', {
defaultType: 'card-button',
height: 38,
region: 'north',
items: [
{
cardType: 'tabpanel1',
text: 'Button 1'
}, {
cardType: 'tabpanel2',
text: 'Button 2'
}, {
cardType: 'tabpanel3',
text: 'Button 3'
}, {
cardType: 'tabpanel4',
text: 'Button 4'
}, {
cardType: 'tabpanel5',
text: 'Button 5'
}, {
cardType: 'tabpanel6',
text: 'Button 6'
}, {
cardType: 'tabpanel7',
text: 'Button 7'
}
]
});
var cardPanel = Ext.create('Ext.panel.Panel', {
activeItem: 0,
border: false,
items:[{xtype: 'tabpanel1'}],
layout: 'card',
margins: '0 0 0 2',
region: 'center'
});
var viewport = Ext.create('Ext.Viewport', {
id: 'border-example',
layout: 'border',
items: [
northTb,
{
collapsed: true,
collapsible: true,
height: 100,
margins: '0 0 0 0',
maxSize: 200,
minSize: 100,
region: 'south',
split: true,
title: 'South'
}, {
activeTab: 2,
animCollapse: true,
collapsible: true,
margins: '0 5 0 0',
maxSize: 400,
minSize: 175,
region: 'east',
split: true,
tabPosition: 'bottom',
title: 'East Side',
width: 225, // give east and west regions a width
xtype: 'tabpanel',
dockedItems: [{
dock: 'top',
xtype: 'toolbar',
items: [
'->',
{
text: 'test',
tooltip: 'Test Button',
xtype: 'button'
}
]
}],
items: [
{
autoScroll: true,
html: '<p>A TabPanel component can be a region.</p>',
title: 'A Tab',
xtype: 'component'
}, {
autoScroll: true,
html: '<p>A TabPanel component can be a region.</p>',
title: 'A Tab',
xtype: 'component'
},
Ext.create('Ext.grid.PropertyGrid', {
closable: true,
title: 'Property Grid',
source: {
'(name)': 'Properties Grid',
'grouping': false,
'autoFitColumns': true,
'productionQuality': false,
'created': Ext.Date.parse('10/15/2006', 'm/d/Y'),
'tested': false,
'version': 0.01,
'borderWidth': 1
}
})
]
}, {
animCollapse: true,
collapsible: true,
id: 'west-panel', // see Ext.getCmp() below
layout: 'accordion',
margins: '0 0 0 5',
maxWidth: 400,
minWidth: 175,
region: 'west',
split: true,
stateId: 'navigation-panel',
title: 'West',
width: 200,
items: [
{
iconCls: 'nav',
items: [{xtype: 'tree1'}],
title: 'Navigation'
}, {
iconCls: 'settings',
items: [{xtype: 'tree2'}],
title: 'Settings',
xtype: 'lazy-panel'
}, {
iconCls: 'settings',
items: [{xtype: 'tree3'}],
title: 'Advanced',
xtype: 'lazy-panel'
}, {
iconCls: 'settings',
items: [{xtype: 'tree4'}],
title: 'Misc',
xtype: 'lazy-panel'
}, {
iconCls: 'settings',
items: [{xtype: 'tree5'}],
title: 'Admin',
xtype: 'lazy-panel'
}
]
},
cardPanel
]
});
var end = new Date().getTime() - start;
setTimeout(function() {
alert(end);
}, 1000);
});
</script>
</head>
<body>
<div id="center7" class="x-hide-display">
<a id="hideit" href="#">Toggle the west region</a>
<p>My closable attribute is set to false so you can't close me. The other center panels can be closed.</p>
<p>The center panel automatically grows to fit the remaining space in the container that isn't taken up by the border regions.</p>
<hr>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed metus nibh, sodales a, porta at, vulputate eget, dui. Pellentesque ut nisl. Maecenas tortor turpis, interdum non, sodales non, iaculis ac, lacus. Vestibulum auctor, tortor quis iaculis malesuada, libero lectus bibendum purus, sit amet tincidunt quam turpis vel lacus. In pellentesque nisl non sem. Suspendisse nunc sem, pretium eget, cursus a, fringilla vel, urna. Aliquam commodo ullamcorper erat. Nullam vel justo in neque porttitor laoreet. Aenean lacus dui, consequat eu, adipiscing eget, nonummy non, nisi. Morbi nunc est, dignissim non, ornare sed, luctus eu, massa. Vivamus eget quam. Vivamus tincidunt diam nec urna. Curabitur velit. Quisque dolor magna, ornare sed, elementum porta, luctus in, leo.</p>
<p>Donec quis dui. Sed imperdiet. Nunc consequat, est eu sollicitudin gravida, mauris ligula lacinia mauris, eu porta dui nisl in velit. Nam congue, odio id auctor nonummy, augue lectus euismod nunc, in tristique turpis dolor sed urna. Donec sit amet quam eget diam fermentum pharetra. Integer tincidunt arcu ut purus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla blandit malesuada odio. Nam augue. Aenean molestie sapien in mi. Suspendisse tincidunt. Pellentesque tempus dui vitae sapien. Donec aliquam ipsum sit amet pede. Sed scelerisque mi a erat. Curabitur rutrum ullamcorper risus. Maecenas et lorem ut felis dictum viverra. Fusce sem. Donec pharetra nibh sit amet sapien.</p>
<p>Aenean ut orci sed ligula consectetuer pretium. Aliquam odio. Nam pellentesque enim. Nam tincidunt condimentum nisi. Maecenas convallis luctus ligula. Donec accumsan ornare risus. Vestibulum id magna a nunc posuere laoreet. Integer iaculis leo vitae nibh. Nam vulputate, mauris vitae luctus pharetra, pede neque bibendum tellus, facilisis commodo diam nisi eget lacus. Duis consectetuer pulvinar nisi. Cras interdum ultricies sem. Nullam tristique. Suspendisse elementum purus eu nisl. Nulla facilisi. Phasellus ultricies ullamcorper lorem. Sed euismod ante vitae lacus. Nam nunc leo, congue vehicula, luctus ac, tempus non, ante. Morbi suscipit purus a nulla. Sed eu diam.</p>
<p>Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras imperdiet felis id velit. Ut non quam at sem dictum ullamcorper. Vestibulum pharetra purus sed pede. Aliquam ultrices, nunc in varius mattis, felis justo pretium magna, eget laoreet justo eros id eros. Aliquam elementum diam fringilla nulla. Praesent laoreet sapien vel metus. Cras tempus, sapien condimentum dictum dapibus, lorem augue fringilla orci, ut tincidunt eros nisi eget turpis. Nullam nunc nunc, eleifend et, dictum et, pharetra a, neque. Ut feugiat. Aliquam erat volutpat. Donec pretium odio nec felis. Phasellus sagittis lacus eget sapien. Donec est. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;</p>
<p>Vestibulum semper. Nullam non odio. Aliquam quam. Mauris eu lectus non nunc auctor ullamcorper. Sed tincidunt molestie enim. Phasellus lobortis justo sit amet quam. Duis nulla erat, varius a, cursus in, tempor sollicitudin, mauris. Aliquam mi velit, consectetuer mattis, consequat tristique, pulvinar ac, nisl. Aliquam mattis vehicula elit. Proin quis leo sed tellus scelerisque molestie. Quisque luctus. Integer mattis. Donec id augue sed leo aliquam egestas. Quisque in sem. Donec dictum enim in dolor. Praesent non erat. Nulla ultrices vestibulum quam.</p>
<p>Duis hendrerit, est vel lobortis sagittis, tortor erat scelerisque tortor, sed pellentesque sem enim id metus. Maecenas at pede. Nulla velit libero, dictum at, mattis quis, sagittis vel, ante. Phasellus faucibus rutrum dui. Cras mauris elit, bibendum at, feugiat non, porta id, neque. Nulla et felis nec odio mollis vehicula. Donec elementum tincidunt mauris. Duis vel dui. Fusce iaculis enim ac nulla. In risus.</p>
<p>Donec gravida. Donec et enim. Morbi sollicitudin, lacus a facilisis pulvinar, odio turpis dapibus elit, in tincidunt turpis felis nec libero. Nam vestibulum tempus ipsum. In hac habitasse platea dictumst. Nulla facilisi. Donec semper ligula. Donec commodo tortor in quam. Etiam massa. Ut tempus ligula eget tellus. Curabitur id velit ut velit varius commodo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla facilisi. Fusce ornare pellentesque libero. Nunc rhoncus. Suspendisse potenti. Ut consequat, leo eu accumsan vehicula, justo sem lobortis elit, ac sollicitudin ipsum neque nec ante.</p>
<p>Aliquam elementum mauris id sem. Vivamus varius, est ut nonummy consectetuer, nulla quam bibendum velit, ac gravida nisi felis sit amet urna. Aliquam nec risus. Maecenas lacinia purus ut velit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse sit amet dui vitae lacus fermentum sodales. Donec varius dapibus nisl. Praesent at velit id risus convallis bibendum. Aliquam felis nibh, rutrum nec, blandit non, mattis sit amet, magna. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam varius dignissim nibh. Quisque id orci ac ante hendrerit molestie. Aliquam malesuada enim non neque.</p>
</div>
</body>
</html>
@skirtle
Thanks for taking the time to refactor the test case. There's a lot of re working in there!!!
Timings wise, I get an improvement. As follows (using 4.1.2)
IE8 Before : 12.087 Seconds
IE8 After : 6.018 Seconds
Chrome Before : 2.753 Seconds
Chrome After : 2.033 Seconds
So approximately halving the load time under IE 8 using the lazy load. So this is great optimisation. Now, I certainly don’t want to take anything away from this because the technique is very useful, certainly in this case (away form the real world) using Ext.define has worked great. So for Dev’s that are in a hole and really need a workaround, this seems a viable option.
My observations are
1. Using Ext.define in this test case means that only the visible components are being created, essentially in these benchmarks we are comparing loading the full app (before changes) and loading a smaller app (after changes). So, it’s not really apple for apples but in terms of framework performance, only app load time are improved.
Anyway this is a step up from using deferredRender and it’s a shame there isn’t a deferredCreate option that can be set, this would be an awesome improvement to the framework. I’ve worked through an add/destroy (memory management) function (with the assistance of [email protected] and [email protected]) which cleans up components as the user move away from a tab. I suggested that I would be a good function to add to the framework, however they felt it was best left to the user to implement. I think now that Ext.define has been demonstrated to be so effective at reducing load times, I think having both a deferredCreate and then add & destroy clean up function in the framework as a configurable option would be a big win for Sencha!
2. Migrating to Ext.define would be a big job for a sizable application.
3. Once the app has loaded and the user has navigated around it, the UI will be just as sluggish as it was my original test app.
Side by side “load times” (not UI performance), Ext 3.4 vs Ext 4.1.2
IE 8 (EXT 3.4) : 4.228 Seconds
IE8 (EXT 4.1.2) : 6.018 Seconds
Chrome (EXT 3.4) : 1.829 Seconds
Chrome (EXT 4.1.2) : 2.033 Seconds
So as you can see, 3.4 (and this is the kicker) which is loading the whole test app, is out performing 4.1.2 which is loading a tiny part of the test app.
As I said earlier, I think Ext.define is a great technique however there’s still a good way to go because the UI performance in 4.1.2 (under IE especially) is a huge way off where is need to be for the production environment and huge way off what Ext 3.4 is.
Best and thanks again!
MrSparks
Thanks for running the benchmarks.
When you say 4.1.2 I assume you mean the nightly build? I don't think 4.1.2 has been released yet.
Would you mind doing another test - could you move the timing code to the start of the main script tag, so that it doesn't include the library loading time, for both 3 and 4? I'd be curious to see where you're seeing the time difference before I start thinking about other ways to optimize it. Think I might try to dig my old computer out of the cupboard, see whether I can get times comparable to the ones you're seeing.
Regarding comparing apples with apples, I apologise if I gave the wrong impression, I never intended to try to prove that 4 is faster than 3, it clearly isn't. I was merely following up on your comment that you didn't believe the test case could be optimized further. If you want to compare 3 to 4 I'd personally try to slow the test case down as much as possible, turning off all the deferring. It'll make for a terrible app but a better comparison.
My use of Ext.define isn't really what makes it faster. You can achieve exactly the same effect without using Ext.define, you just need the lazy instantiation. I broke things into classes just because the code made my head spin without proper classes. It'd probably be slightly faster if I hadn't broken it up so much but removing the overhead of defining the classes didn't seem a realistic optimization for a real app.
Not sure I follow. Do you mean upgrading from 3 to 4? Possibly true but I'm not sure this is really relevant to the performance debate. The use of classes to segment your code is pretty much unavoidable for non-trivial applications.Quote:
2. Migrating to Ext.define would be a big job for a sizable application.
@skirtle
No problem at all. Here are the revised timings with the start timer moved below the framework js file.
I'm running nightly build 4.1.2.268
Ext4.1.2 (after) > 5.131 Seconds
Ext3.4 > 4.227 Seconds
Moving the timings has reduced 4.1.2's load time by 1 second. There has been no noticiable effect on 3.4
Quote:
2. Migrating to Ext.define would be a big job for a sizable application.
I was referring to the time it would take to refactor an existing 4.x app to the Ext.define method, rather than migrating from 3.4 upwards. However after reading your reply that's not required.
With regards to lazy instantiation (related to the above comment). So using xtype is lazy instantiation?
i.e. This is not Lazy
Code:var myTree = new Ext.tree.Panel ({
store: store,
rootVisible: false,
useArrows: true,
frame: true,
title: 'Check Tree',
width: 200,
height: 250,
dockedItems: [{
xtype: 'toolbar',
items: {
text: 'Get checked nodes',
handler: function(){
var records = tree.getView().getChecked(),
names = [];
Ext.Array.each(records, function(rec){
names.push(rec.get('text'));
});
Ext.MessageBox.show({
title: 'Selected Nodes',
msg: names.join('<br />'),
icon: Ext.MessageBox.INFO
});
}
}
}]
});
However this is Lazy
Code:items: [{
xtype: 'treepanel',
store: store,
rootVisible: false,
useArrows: true,
frame: true,
title: 'Check Tree',
width: 200,
height: 250,
dockedItems: [{
xtype: 'toolbar',
items: {
text: 'Get checked nodes',
handler: function(){
var records = tree.getView().getChecked(),
names = [];
Ext.Array.each(records, function(rec){
names.push(rec.get('text'));
});
Ext.MessageBox.show({
title: 'Selected Nodes',
msg: names.join('<br />'),
icon: Ext.MessageBox.INFO
});
}
}
}]
}]
Question if this is the case, can the lazy loaded config be declared as "var" like the none Lazy version? My understanding was "there's no such thing as "lazy instantiation"
http://www.sencha.com/forum/showthre...l=1#post519069
Best
MrSparks
Yep, I would sign this.
Looking back at our migration (a very, very big app), the time spent on transforming to ExtJS4's Ext.define wasn't the big one (incl. preferred usage of this.callParent()). Certainly, we had already a component structure (one component per file, namespace follows directorys.. the Java style) because it would not be manageable at all.
But the other API changes (rowselector's events, 4.1's beforerender/afterrender differences, TreeStore/TreePanel changes) were a lot more detail work and had required much more fine tuning, migration or fixing.
We had (or have) performance issues in browsers (and especially IE8 & 9). I will share the following advices (will apply for all browsers, but IE will win a lot)
- Avoid using Ext.each, prefer native for-loops (IE!). This includes Ext.data.Store.each, too.
So, yes: This is good: var items = this.query('fieldset'), i = 0; for (; i < items.length; i++) {console.info(items[i]);}- We'd followed the advice avoiding containers which are superfluous and or have the Border Layout.
I cannot they that this were the big impacts.. however, it is possible that they can be added to the sum of optimizations.- Avoid adding/removing components on the fly if possible and do not (well, I mean never) make this in a loop.
If you still have to do this: Ext.suspendEvents()/resumeEvents(true).- Avoid miss using components, use (simple) templates if possible.
We had a bigger construct of button groups and buttons within a panel which needed several seconds (benchmark with 70 components, each 2-3 buttongroups and overall 700 buttons needs a lot of time regardless the Ext.suspendEvents()-hack). Avoiding this show stopper (and actually, bad component design) I've rewritten this into one component with exactly one template. Same benchmark data, the stuff is rendered under a second or two (including loaded).- Avoid loading much data into the tree store, use asynchronous remote loading.
We've had a bigger (but dynamic) tree which kills the IE (an IE8 fetching 800 MB RAM is far away from being responsible until the loading/rendering is finished after minutes!). The new tree fetches only one level (or the selected path). This is actually faster than before. However, this requires a dynamic "tree shadow cache" server side.- Overall a bad pattern: On key event like "select" (or selectionchange) calling an unbuffered call to the UI or store actions.
At first, it will improve the UI responsive if the event would be called delayed. And secondly, this avoids multiple, but competitive, calls to the same stuff (loading a store multiple times with different parameters because the user has reselected many times.
As seen in this forum post, the code below can dramatically increase performance in IE9:
Code:Ext.onReady(function() {
if (Ext.isIE) {
Ext.supports.Direct2DBug = false;
}
});
4.1.2 GA, The release notes don't refer to any Performance gains. Can you confirm what the status of this issue is?
4.1.2 was supposed to be a performance release, it just looks like a stack of bug fixes..?
Regards
MrSparks
Yes, 4.2 is the next significant release for performance work.
Please see http://www.sencha.com/forum/showthre...ents-in-4.next
No official date, but St. Nick might be bringing something extra in his sleigh ...
It is not that we will reject changes that only have performance gains in 4.1.x, but we have to be sure that each release of 4.1.x is a stability improvement over the previous. So we are just going to be cautious there and hence won't be taking on the larger/riskier changes on that branch.
I don't see how the emphasis is different there. We are going to have performance improvements in 4.1.x and 4.2 but with different levels of risk tolerance and pro-activity.
With 4.2 we will have a beta process to help vet out changes and fix regressions. We don't have that (really) with 4.1.x releases. That allows us to take on more risk in 4.2.
I understand your caution and see the necessity. However, Mullany was putting the emphasis on fixing the performance problems "as aggressively as possible" ... "until we achieve our performance goals." I'm quite concerned considering that in his comments in the blog on how to achieve performance on v4, Animal stated
"In my opinion, the performance restriction now is entirely imposed by the Javascript engine being used."
There were some direct responses to this claim, but nothing further from Sencha. I'm counting on the fact that Animal's opinion is not the official Sencha position, but I get nervous when the next build released does not apparently address performance at all...
We do have an aggressive timeline for 4.2 if that helps, but I certainly understand your concern.
The comment you cite is not an official statement from Sencha on what is possible in this regard. That statement is just a "tautology" - performance of JS code is always limited by the performance of the JS engine. :)
That does not mean the JS code in question cannot accomplish its required results faster or more efficiently. In early work on several of these areas, we are clearly seeing that further, significant improvement is possible. If any of those experiments can be "back-ported" to 4.1.x, we will certainly consider doing so.
I have to say I am really disappointed about the state and performance of ExtJS 4. When the first test releases came out I immediately started testing it. The stabilization proces was long and painful though. During Sencha Con 2011, the grid performance problems were already known but they were presented like solvable in the near future. ExtJS 4 was still being presented as the most stable and fast ExtJS to date.
This thread and my own experiences however tell a different tale. Seeing how long it takes Sencha to solve the performance problems, I think the problems (most serious on IE but also other browsers) are here to stay and cannot be solved.
Because of the problems I have had to start porting back a very complex workflow management system I created for an international bank since they cannot switch to another browser than IE8. The performance of the system under IE8 is horrible both in memory usage as CPU usage, especially with components utilizing one or more grids. Choosing ExtJS 4.1 for the new system has cost my company a lot of time and money, and has caused the project to be seriously delayed. All that does not instil confidence in my client, for whom I have gone to great lengths to convince them to deploy the application using ExtJS4 (the previous version I created using ExtJS 3.4 which runs snappy).
I think it is time Sencha gives this problem serious effort since the credibility and businesses of developers using ExtJS is at stake. I know Sencha is working on it, but is also starting up a new product line every other day it seems. Everybody knows you cannot focus on too many things at the same time.
Rob Boerman
Interesting, picking up this thread again... and some nice ideas and tips from posters; the lazy panel/container is interesting, might try it and see where that can take us. At the very least it should raise some eyebrows in the dev team, causing them to ask what effort is being wasted early in the process there.
Another good thought was on avoiding the use of many components, and instead using a single one with a custom template... could be useful for docked items on grids, say, where we're certainly seeing some issues (see my colleagues post on button layout being very expensive).
Would also like to add my voice to those calling for more emphasis on performance of Ext 4 in old IE's, rather than the constant release of new products.
I know decent performance is your goal for Ext 4, I just wish it'd take a higher priority, and you'd stop tinkering with toys and concentrate on it. Apologies to those with business applications running on phones and tablets, but I think you are probably a very small minority. Those using Ext 4 are the people paying for licenses after all, well, commercially at least.
Whilst examples are all very well and good, the real world uses real applications to get a job done, and in the corporate world people do not have the luxury of using Chrome, FF or Safari... at least not yet.
The best we can generally hope for is IE8, and sometimes, with especially forward thinking companies, IE9.
IE7 is definitely the norm though, for us at least, and those who have dealt with it will know that it's about 30-50% slower than IE8 even.
Progress is being made though I think, but as others have pointed out, there is still some way to go.
The issues have definitely influenced how we design our UIs though; always in the back of my mind is how features x, y and z will work in IE.
Look forward to hearing more on Ext 4.2.
4.1.1 or 4.1.2 have not been good enough for me to upgrade to, so hope 4.2 is...
Cheers,
Westy
Its disappointing that large corporates cant move past MS and IE.
http://gs.statcounter.com/#browser-ww-monthly-200808-201208
IE 10 may turn the tide.
It is such a huge pain to cater for old browsers that cant perform - I know it is what it is
arggggggggghhhhhhhhhhhhhhh
I agree, it's disappointing... the best we can hope for is when XP support ends in February 2014, although big corps will no doubt pay MS to continue support.
IE10 may turn the tide for consumers, but I can't see any large company upgrading to Windows 8 rather than 7, the support calls over how to shutdown the machine will cost them a fortune alone!
So, post Feb 2014 the worst browser we may get away with supporting might be IE9, although the initial versions of Windows 7 had IE8, so even that may not help...
yes your right.
I worked for a bank for 7 years and it drove me nuts the dedication to IE (took an age to get an upgrade from IE 6.0 to IE8).
A simple switch to a more html5 compliant browser makes all the difference.
Never mind - no use banging our heads against the wall.
Yes your right - conversion for corporates to windows 8 in unlikely. Win 7 will become the new XP pro and corporates will hang on to win 7 for dear life - until we see a stable Win 8+
So hope for IE10 a long way off.
Sill it worth the frustrating scream ..... arghhhhhhhhhhhhhhhhhhhh
Just a sigestion, did you consider this thread:
http://www.sencha.com/forum/showthre...ent-suggestion
So how far off is 4.2 beta? Is this available now for users with a support license? Is there a large performance gain for IE7 & IE8?
IE8 is here for the long haul in the corporate sphere. IE9 has a non-zero risk of introducing issues (quite a big risk in my experience), and so all web apps need to be recertified in places where certification matters. Many of the customers I deal with (banks and telecom) have such a certification process. Some are still in the planning stage of a migration from IE6 to IE8. W7+IE8 doesn't lose official support until 2020, and with IE6 we saw that many corporations were ok with playing it close to the limit, so my outlook on that is bleak.
ExtJS has to run "acceptably well" on IE8. It does on 3.4. It should on 4.x. I'm still on 3.4 and will not upgrade to 4.x until I see some convincing communication that the performance issues are solved.
Is it possible that someone from the Sencha team informs us about the status of the performance issues?
- Is a performance update underway and when can we expect it?
- Does the 4.1.2 update include any performance improvements?
My problems with clients are getting so big that we have to start thinking about alternatives to ExtJS. Please let me, and the rest of us, know how this problem is being tackled and keep us in the loop.
@robboerman. I don't believe 4.1.2 included any significant performance improvements. See this post for the main areas that are being targeted for 4.2:
http://www.sencha.com/forum/showthread.php?242202
4.2 been out. Are people seeing better performance with 4.2? For me, it's about as slow as before.
To me, 4.2 still doesn't perform well at all under IE8, especially tab panel rendering time and tab switching, also nested panels rendering is still way slower than extjs 3.4. the only componend which work well is the grid panel.
4.2 is still unusable for big applications in IE8
(performance seem ok in other browsers, at least on my core i7-2600 CPU)
I sure hope this eventually gets addressed. After spending months upgrading our app from 3.x to 4.x our customers (95% are stuck on IE8) have nothing but bad things to say about the degradation of performance of our "new version". For example, grid with ~20 columns each with a filter (grid filter feature). Remote paging with only 50 rows per page, so not big number of rendered rows. Grid header menus take 5 seconds to appear after clicking the header menu arrow. When moving the mouse over the menu items there is a two second pause before focus switches to the next menu item.
Switching to "Compatibility Mode" help a little, but why should that be needed?
I just can't understand how something like this that has been reported for so long goes unaddressed. I could care less about BufferedRenderer. It's not the number of rows that is causing the issue otherwise we wouldn't be seeing it with just 50 rows per page.
At this point our 4.x subscription has been a disappointment. Months of upgrade work will be thrown out as we revert back to our 3.x codeline.
Make good use of Ext.suspendLayouts and Ext.resumeLayouts and it should be much quicker. Wont be as fast as 3.x but your reported times are really bad...
Haven't upgraded EXTJS for 3 releases. We are on 4.1.2. 4.1.3 had a serious bug relative to dynamically building accordions which made it unusable for us. 4.2.0 had a bug in IE 8 where EXTJS was making http requests under our https app which caused an ugly IE dialog to popup every page refresh. And 4.2.1 had a lot of issues for us that were working perfectly on our current 4.1.2 release.
One thing I can say about 4.2.1 is that the grids and trees are noticeably faster under IE 8. I would strongly agree with the prior post that the suspendLayout call makes a huge performance difference in some cases.
Thanks for the suspendLayouts suggestion, but our main pain point seems to be with showing grid header menus and their associated filters. Don't think I can utilize that in this case. I looked at the code for ListMenu and I see it is using suspendLayouts at the appropriate points. I wish I could get a better handle on why exactly when I try to drop the grid header menu down that it is taking so long, but I have been unsuccessful there.
The grid itself displays reasonably fine, but the header menu performance is just unbearable. Compatibility Mode makes it somewhat better which I guess offers a clue.
If it is very specifically showing a menu that is slow then theres something very strange going on. I can't see how showing a menu could cause anything bad. It has to lay out the menu, but while slower on IE, laying out one menu should not be noticeable.
There must be some events firing which fire off into some other complex stuff.
Can you show a test case? Does it happen in the example page at examples/grid-filtering/grid-filter-local.html ?
Best thing would be to run Chrome's profiler during the click of the header menu trigger so that we can see the call stack and the time taken in each level.
Once we see where the time is going it should be easy to fix.
I am not 100% sure, but this looks quite related to the "header menu in IE" problem you are discussing.
http://www.sencha.com/forum/showthread.php?245478