Everything tagged animal (1 post)

Sencha Con 2013: Ext JS Performance tips

Just as with Jacky's session, I didn't plan on making a separate post about this, but again the content was so good and I ended up taking so many notes that it also warrants its own space. To save myself from early carpal tunnel syndrome I'm going to leave this one in more of a bullet point format.

Ext JS has been getting more flexible with each release. You can do many more things with it these days than you used to be able to, but there has been a performance cost associated with that. In many cases this performance degradation is down to the way the framework is being used, as opposed to a fundamental problem with the framework itself.

There's a whole bunch of things that you can do to dramatically speed up the performance of an app you're not happy with, and Nige "Animal" White took us through them this morning. Here's what I was able to write down in time:

Slow things

Nige identified three of the top causes of sluggish apps, which we'll go through one by one:

  • Network latency
  • JS execution
  • Layout activity

Network latency:

  • Bad ux - got to stare at blank screen for a while
  • Use Sencha Command to build the app - single file, minimized
  • 4810ms vs 352ms = dynamic loading vs built

JavaScript execution:

  • Avoid slow JS engines (he says with a wry smile)
  • Optimize repeated code - for loops should be tight, cache variables outside
  • Ideally, don't do any processing at render time
  • Minimize function calls
  • Lazily instantiate items
  • Use the PageAnalyzer (in the Ext JS SDK examples folder) to benchmark your applications
  • Start Chrome with --enable-benchmarking to get much more accurate timing information out of the browser

Layouts

Suspend store events when adding/removing many records. Otherwise we're going to get a full Ext JS layout pass for each modification

grid.store.suspendEvents();
//do lots of updating
grid.store.resumeEvents();
grid.view.refresh()

grid.store.suspendEvents();
//do lots of updating
grid.store.resumeEvents();
grid.view.refresh()

Ditto on trees (they're the same as grids) Coalesce multiple layouts. If you're adding/removing a bunch of Components in a single go, do it like this:

Ext.suspendLayouts();
//do a bunch of UI updates
Ext.resumeLayouts(true);

Ext.suspendLayouts();
//do a bunch of UI updates
Ext.resumeLayouts(true);

Container#add accepts an array of items, which is faster than iterating over that array yourself and calling .add for each one. Avoid layout constraints where possible - in box layouts, align: 'stretchmax' is slow because it has to do multiple layout runs. Avoid minHeight, maxHeight, minWidth, maxWidth if possible

At startup:

  • Embed initialization data inside the HTML if possible - avoids AJAX requests
  • Configure the entire layout in one shot using that data
  • Do not make multiple Ajax requests, and build the layout in response

Use the 'idle' event

  • Similar to the AnimationQueue
  • Ext.globalEvents.on('idle', myFunction) - called once a big layout/repaint run has finished
  • Using the idle listener sometimes preferable to setTimeout(myFunction, 1), because it's synchronous in the same repaint cycle. The setTimeout approach means the repaint happens, then your code is called. If your code itself requires a repaint, that means you'll have 2 repaints in setTimeout vs 1 in on.('idle')

Reduce layout depth

Big problem - overnesting. People very often do this with grids:

{
xtype: 'tabpanel',
items: [
{
title: 'Results',
items: {
xtype: 'grid'
}
}
]
}
{
xtype: 'tabpanel',
items: [
{
title: 'Results',
items: {
xtype: 'grid'
}
}
]
}

Better:

{
xtype: 'tabpanel',
items: {
title: 'Results',
xtype: 'grid'
}
}
{
xtype: 'tabpanel',
items: {
title: 'Results',
xtype: 'grid'
}
}

This is important because redundant components still cost CPU and memory. Everything is a Component now - panel headers, icons, etc etc. Can be constructing more Components than you realize. Much more flexible, but easy to abuse

Lazy Instantiation

New plugin at https://gist.github.com/ExtAnimal/c93148f5194f2a232464

{
xtype: 'tabpanel',
ptype: 'lazyitems',
items: {
title: 'Results',
xtype: 'grid'
}
}
{
xtype: 'tabpanel',
ptype: 'lazyitems',
items: {
title: 'Results',
xtype: 'grid'
}
}

Overall impact

On a real life large example contributed by a Sencha customer:

Bad practices: 5187ms (IE8) Good practices: 1813ms (IE8) 1300ms vs 550ms on Chrome (same example)

Colossal impact on the Ext.suspendLayout example - 4700ms vs 100ms on Chrome

Summary

This is definitely a talk you'll want to watch when they go online. It was absolutely brimming with content and the advice comes straight from the horse's mouth. Nige did a great job presenting, and reminded us that performance is a shared responsibility - the framework is getting faster as time goes by, but we the developers need to do our share too to make sure it stays fast.

Continue reading