Sencha Touch: Optimizing Memory Usage
Although most modern mobile devices have good hardware specs, almost all of them are still lacking in areas like memory — especially compared to their desktop counterparts. Others either have weak graphics processing units (GPUs), or the browser doesn’t properly leverage the GPU for animations and drawing. In a previous article, we looked at event delegation as a way of improving the performance of your mobile web application. Event delegation speeds up your app because it reduces the amount of memory your application uses at a given time. Of course, this is not the only thing you can do. In this article, we will look at one more technique that improves your application’s memory usage.
The Size of Your DOM
The number of elements on your page has a large effect on the amount of memory your application uses, so it’s a good idea to keep your DOM as small as possible at all times. “Heavy weight” elements like images should especially be kept to a minimum.
We do have one major advantage: due to the size of screens for mobile devices, the applications on them typically show only a small part of the interface at any given time. This means we can remove the elements related to parts of the app that are not visible anymore. In Sencha Touch, this particularly applies to things like popups, modal windows, and cards in Panels and Carousels. So how can we leverage this knowledge when writing our apps?
In Sencha Touch, there are events that fire when the visual state of a component changes. For example, when you switch cards in a Container with a CardLayout, the Container will fire a cardswitch event once it’s done. We can hook into these events and destroy Components that are not visible anymore because of these transitions.
Let’s look at a simple example. Our goal is to have a List that slides to a details panel whenever you tap on an item. Once we get to the details panel, we want to destroy the List. Then when we go back to the List, we want to destroy the details panel. This way, we ensure the minimum required markup in the DOM at any given time.
Example
Here is an example of the code for the List:
var list = { xtype: 'list', title: 'Contacts', listeners: { itemtap: function(item) { details.html = item.details; panel.setCard(details); } } // list & store configuration ... };
Note the use of xtype. Here, we are not creating an instance of our list, simply a JSON object representing the object. This way we can destroy and recreate our list easily.
We do the same for the details panel, except in this case, we will put a Back button inside the panels top toolbar which will cause the container to show the list again when pressed.
var details = { xtype: 'panel', dockedItems: { title: 'Details', dock: 'top', items: { text: 'Back', ui: 'back', handler: function() { panel.setCard(list); } } } // component configuration ... };
Now, we get to the interesting part. Let’s create the following Panel which will contain our child components.
var panel = new Ext.Panel({ fullscreen: true, layout: 'card', items: [list] });
As you can see, we have created a fullscreen Panel with a layout of card that contains our list by default. We haven’t put in the details panel yet. Instead, we will only insert the details panel when you tap an item.
Now, it’s time to set up a listener to the cardswitch event. This is where we actually ensure that the card we just came from is being destroyed.
panel.on('cardswitch', function(newCard, oldCard) { if (oldCard) { this.remove(oldCard, true); } }, panel);
As you can see, we are removing the old card from the container. By passing true to the second argument of the remove function, the container will call the destroy method on the card—also removing all of the events bound within that object as well as the actual DOM created.
This same concept applies to hiding a modal window or popup. In fact, you can apply this concept to almost any visual state change of your app. Of course, you want to find a balance between reducing your app’s memory usage and rendering heavy components again and again. In some cases, the benefit of not having a long rendered List in memory is offset by having to render a very long list again when you switch back to it.
So far, we have looked at event delegation and DOM cleaning as ways to reduce your applications memory usage. In a future article, we will look at things you can do to improve the performance of your animations. Till then, delegate and keep your DOM clean!

There are 25 responses. Add yours.
Jeff
1 year agoI like this.. I’ve seen my app suck up alot of memory and will see if this helps minimize this issue!
Mitchell Simoens
1 year agoPosted something like this in the forums a month ago. It is a great practice to do this. Animations will be smoother, scrolling will be smoother…. just a much, MUCH better experience for the end user!
Jay Garcia
1 year agoMore people need to read this!! Some of these rules apply to Ext JS as well.
Chris Toppon
1 year agoGreat stuff! Will be trying this out. I had been experimenting using .destroy() to remove panels but have noticed that although this removes the panel from the DOM it seems to be still available in its original object container?
For example I have a panel this.detailPanel in a controller and have a listener on the deactivate to destroy itself:
this.detailPanel = this.render({
xtype: ‘profile-detailpanel’,
listeners: {
deactivate: function(detail) {
detail.destroy();
},
scope: this
}
So in order to test if the panel exists next time before we create it, its not enough to use
if (!this.detailPanel) {...
However I’ve found (looking at the destroy source code) that its possible to use the isDestroyed method to test if it has been previously destroyed:
if (!this.detailPanel || this.detailPanel.isDestroyed) {...
Wondering if this expected / recommended behaviour? Presuming the remove method above destroys the DOM element and the object?
Vidar Vestnes
1 year agoOn Android, I also found that if i put the source code into an simple-skeleton app, having an WebView, the app preforms much better and is a lot less “buggy” compared to running the app directly from and URL in the build in browser. It got nothing to do with the download-process of the source files, since both components (WebView and built-in browser) download all needed files before executing. The WebView just performs way better than the built-in browser, and almost never hangs/halts. I’m not sure why though…
Thomas
1 year ago@Chris Toppon
I’m having similar question as you posted. It seems remove and destroy cleans the DOM, not the variable.
and remove function is used to destroy child items.
Correct me if i’m wrong
Just an addition, we can find total number of nodes using Ext.query(’*’).length.
.
Alex Korn
1 year agoGood post! I noticed a typo: “week graphics processing units” should be “weak”. Also, this page says that the comments are from 5 and 6 days ago even though this post is from today.
Jay Robinson Sencha Employee
1 year agoAlex, you are correct! People who sign up for our newsletter get advanced notice of helpful articles such as this!
Also, fixed the typo, thanks.
Steven Roussey
1 year agoDelayed instantiation???
Such a nag I know… 
George
1 year agoGreat article!
But i was looking at the API and i don’t find any setCard method. I tried the code and i get ‘Result of expression ‘panel.setCard’ [undefined] is not a function.’.
Isn’t it supposed to be insert() instead?.
Tyson Cadenhead
1 year agoHas anyone found a solution to the destroy() method and the delete() method not removing the variable associated with the panel? I’m running into the same thing, and it becomes a problem because Sencha thinks the panel already exists since the ID is registered, but when it renders it, it’s basically just an empty div in the DOM.
james
1 year agoi tried running the code and i get a setCard is not a function error. What is causing this?
Avitodvd
1 year agoYou guys did a great job, but why I can’t run this on my mobile? What’s wrong? Thanks, I using HTC touch phone
jax
1 year agoUseless blog entry because it doesn’t work..
@james: The api is changed. Every day business for Extjs: change the api but leave examples online with obsolete code. Frustrating isn’t it?
z4mb0
1 year agoWhat if i want to recall a card that i already deleted? I tried but it gives error!
Tyson Cadenhead
1 year agoFrom what I’ve seen, the key is to let Sencha generate the id of the card rather than creating the id yourself. If you try to recall a card that has the same id as it did the first time it was called, that’s when the errors start to happen.
Steven
1 year agoThe setCard method does not exist anymore right? So why is this method used in this example? I get this error:
‘Uncaught TypeError: Object [object Object] has no method ‘setCard’‘
Clint
1 year agoThanks for this article—any memory management tips are extremely helpful/important for the Sencha community, I think.
What’s the best way to replicate this in ExtJS, say, with a CardLayout? For example, if I remove a card when it is hidden, do I need to manually re-instantiate it if it is shown again?
Clint
1 year agoIt occurred to me that the Sencha forum might be a better place for my question, so I posted it there (with a code example). Including the link here for anyone that’s interested since it is somewhat related to this article: http://www.sencha.com/forum/showthread.php?132683-Best-way-to-destroy-card-when-hidden-instantiate-when-shown
Chris
1 year agoYes, no method call setCard(), maybe it means panel.setActiveItem(newpanel, ‘slide’);
Pablo
12 months agoIn order to make this work for at least version 1.1.0, is
1. setCard is depracated, you need to use setActiveItem (setCard is still there though).
2. You cannot pass setActiveItem a simple JSON [sic] object. You need to pass a String Id, a Numeric index (as per documentation) or an already instantiated component (Not documented!). So you should make the list and the detail components, which is good practice any way, and to switch a card you need to do a setActiveItem(new foo.bar.List()) or setActiveItem(new foo.bar.Detail()); accordingly.
For this to work you need to pass
Riaz
11 months agowhy back button is not working?
items: {
text: ‘Back’,
ui: ‘back’,
handler: function() {
panel.setActiveItem(list);
}
}
shuh
9 months agoTypo error:
cardswitch : ( Ext.Container this, Ext.Component newCard, Ext.Component oldCard, Number index, Boolean animated )
First parameter “Ext.Container this” is missing.
Kevin
9 months agoPlease note - if you’re getting an error message regarding isValidParent - it’s because you need to use the this.getLayout().remove() in the cardswitch - NOT just this.remove(). Docs are a little outdated but the .remove for the panel seems to not work as documented.
All my errors when away when i inserted the .getLayout().
hope this helps someone.
Kev
kevin
9 months agoDamn - i retract that. It’s working only because getLayout().remove is not defined and i’m not removing items
I’m not sure what’s going wrong. If anyone can point me in the correct direction - that would be great. I’m getting the error when I add a component - switch to it - go back to the first card (which i always keep) and then switch back again (adding the component a second time generates the isValidParent triggering an error)
Comments are Gravatar enabled. Your email address will not be shown.
Commenting is not available in this channel entry.