PhoneGap Training - Optimus Prime
"More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason — including blind stupidity."
— W.A. Wulf
2. Optimus Prime
"More computing sins are committed in the name of
efficiency (without necessarily achieving it) than for any
other single reason — including blind stupidity." —
W.A. Wulf
3. About Me
With Nitobi for the last 3 years
Built many large scale JS Apps for Mobile devices.
PhoneGap contributor ( iOS + WP7 )
6. When should you optimize?
When you notice
performance lag
Often, each iteration
Review at the end
of each release
cycle
7. What to optimize
It has been said that when an application is running,
90% of the time is spent in 10% of the code.
Find the 10%
8. Benchmarking
It is hard to judge improvement without measurement.
console.log("running test 1")
var startTime = new Date().getTime();
/// lots of looping in here
var elapsed = new Date().getTime() - startTime;
console.log("Test 1 took : " + elapsed);
10. What does this tell us?
Run your loops a lot!
Be somewhat realistic
If it ain't broke, don't fix it!
11. Know when to optimize
function doIt(a,b,c,d,e)
{
if(typeof a === "function")
{
a(b,c,d,e);
}
else
{
throw "wtf?";
}
}
12. Minification
There are tools for that
This is an extreme example, but it happens.
Trust me.
Add a minification tool to your build process.
13. Minification Tools
JSMin
http://www.crockford.com/javascript/jsmin.html
YUI Compressor
http://developer.yahoo.com/yui/compressor/
Closure
http://code.google.com/closure/
Minification does not improve execution time of your code!
14. More Tools - Quality
JSLint, by Douglas Crockford
http://www.jslint.com/
JSHint, based on JSLint
http://www.jshint.com/
15. Concatenation
Combining multiple input files into a single file
request can help with load times as well.
PhoneGap uses this technique for the JS code
in phonegap.js.
16. More coding tips :
Dereference long
variables
or frequently used
variables with a local
alias.
17. Long object reference
ex. ( Bad )
function findUserById(id)
{
for(var n = 0; n < app.model.userInfo.contacts.length; n++)
{
if(app.model.userInfo.contacts[n].id === id)
{
return app.model.userInfo.contacts[n];
}
}
}
18. Dereferenced Object Alias
ex. ( Better )
function ndUserById(id)
{
var contacts = app.model.userInfo.contacts;
for(var n = 0, len=contacts.length; n < len; n++)
{
if(contacts[n].id === id)
{
return contacts[n];
}
}
}
19. What really happens with
long object chains:
Because we store a local alias to the contacts array, we
don't have to dereference repeatedly.
app.model.userInfo.contacts
find a var named 'app'
find a property named 'model'
find a property named 'userInfo'
find a property named 'contacts'
20. Using the right container
-- assuming ids are unique in the
contacts list :
function findUserById(id)
{
// no searching ...
return
app.model.userInfo.contacts[id];
}
21. // and when we received them from the server, we probably
// got them like this:
// Bad?
function onServerResult(res)
{
for(var n = 0; n < res.length; n++)
{
var contact = JSON.parse(res[n]);
app.model.userInfo.contacts[contact.id] = contact;
}
}
22. // what about lifting?
// that's better
function onServerResult(res)
{
var contacts = app.model.userInfo.contacts;
var contact;
for(var n = 0; n < res.length; n++)
{
contact = JSON.parse(res[n]);
contacts[contact.id] = contact;
}
}
24. Switch on Boolean
// validate a form
switch(true)
{
case ( usernameTxt.value == null) :
// set error message, set focus, ...
return false;
case ( passwordTxt.value == null) :
return false;
case ( passwordTxt.value != password2Text.value)
return false;
}
Always put your most likely cases rst, to avoid extra processing.
Exit as soon as possible, if you found it, then stop looking.
25. Key questions to ask
Is the performance really that bad?
Perception is key.
Does your app remain responsive?
26. var processedIndex = 0;
var jobs = [];
function processNextValue()
{
if(processedIndex < jobs.length)
{
doJob(jobs[processedIndex++]);
setTimeout(processNextValue,1);
}
}
function doJob(job)
{
// assume some short bit of work here
}
function onTouchStart(e)
{
// you could even pause your processing in here
}
function onCancelButton(e)
{
// cancel your jobs
}
27. On to the DOM
The DOM is your friend, be nice to it!
28. A common performance
killer is this nasty tidbit :
for(var n = 0; n < results.length; n++)
{
var elementMarkup = "<li class='resultItem'>" + results[n] + "</li>";
document.getElementById("resultList").innerHTML += elementMarkup;
}
29. Prepare your updates to the
DOM
var elementsMarkup = "";
for(var n = 0; n < results.length; n++)
{
elementsMarkup += "<li class='resultItem'>" + results[n] + "</li>"
}
document.getElementById("resultList").innerHTML += elementsMarkup;
Now we are only modifying the DOM once, and it can
be updated quickly.
30. DOM best practices
if you can avoid using css gradients, then drop them.
They are heavy to render, especially in scrolling lists.
avoid transparency where possible. If an item is
transparent, the stuff behind it needs to be rendered too.
use 3D transforms for moving/sliding DOM elements.
Most newer devices use hardware acceleration for 3D
transforms. Essentially you will just throw away the Z.
ex.
Slide right :
element.style.webkitTransitionDuration = "600ms";
element.style.webkitTransform = "translate3D(-320px,0px,0px)";
An example of this later.
31. Sprite Sheets
Instead of loading many small icons, or UI elements as
separate images, consider compositing them into one
image file and using css properties to manipulate what
area is shown.
http://www.tutorial9.net/tutorials/web-tutorials/building-
faster-websites-with-css-sprites/
And there are tools to help you.
http://spritegen.website-performance.org/
... many out there, look around.
32. Using Libraries
There are millions out there! ( okay, hundreds )
Most will work with PhoneGap
jQuery Mobile - the big name
Sencha Touch - rich interaction
Dojo Mobile
XUI - Nitobi’s own
- Nitobi's own
33. Do you need a UI framework?
You may not need a full blown UI Framework, there are
also lighter options to consider.
Backbone.js gives you a nice scaffold, and helpers for
managing your app.
Underscore.js is JS utility belt, helpers for function
binding, ...
34. That elusive scrolling
iScroll4
My favorite scrolling library ( even over my own )
A very common request, how do we make some things scroll,
while other things don't?
iScroll works with iOS and Android, and has no
dependancies.
Follow a few simple rules, and you can have nice scrolling
content with scrollbars.
36. General Considerations
follow MVC conventions, and keep a clear separation
between the views of your app.
keep things async, and try to implement
eventListeners, or some notification system.
scripts at the bottom!
37. More Crazy Goodness
// Write your own query selector
function $(query)
{
return document.querySelectorAll(query);
}
More here :
http://cubiq.org/do-you-really-need-jquery-for-mobile-dev
38. Function.prototype.bind = function(sub)
{
var me = this;
return function(){ return me.apply(sub, arguments);};
};
Just call like this :
someObject.myFunk = function()
{
// this is this of someObject
}
someObject.doLater = function()
{
setInterval( this.myFunk.bind(this),1000);
}