Please interrupt me.
There is a general perception that apps built using HTML, CSS, and JavaScript are slow. (Hint: We are going to change that in this session)
Because science!
// The Basics
Apache Cordova apps are written in HTML, CSS, and JavaScript that can also access native device capabilities.
Cordova apps are web applications that run inside a native application. This allows you to use HTML, CSS, and JavaScript to build your app while still having access to your device’s hardware capabilities! Native Wrapper Your JavaScript App Cordova Plugin JS API
What does it mean for something to be fast and responsive?
Interaction Classes
What we care about!
Methodology
1. The Webview Tax 2. Document Object Model (DOM) 3. Images 4. Animation 5. Garbage Collection 6. UI Controls
// The Webview Tax
// Document Object Model (DOM)
Bad Alpha Zeta Tao Epsilon
Good Alpha Zeta Tao Epsilon
Layout Thrashing
Bad for (var i = b.children.length - 1; i >= 0; i--) { b.children[i].style.left = b.children[i].offsetLeft + "px"; b.children[i].style.top = b.children[i].offsetTop + "px"; }
Good for (var i = b.children.length - 1; i >= 0; i--) { topPx[i] = b.children[i].offsetTop; leftPx[i] = b.children[i].offsetLeft; } for (var i = b.children.length - 1; i >= 0; i--) { b.children[i].style.left = leftPx[i] + "px"; b.children[i].style.top = topPx[i] + "px"; }
Fast List Scrolling
Memory Usage: Virtualized List vs. Non-Virtualized List
Use virtualization When working with large amounts of data, only work with the data you need to display content on the screen. (Popular control frameworks like WinJS, Ionic, Onsen UI, Kendo UI and others help handle this for you.)
// Images
Gradients
Bad.css_gradient { background: -webkit-linear-gradient(top,rgb(84, 1, 1),rgb(0, 84, 119)); /*Safari 5.1-6*/ background: -o-linear-gradient(top,rgb(84, 1, 1),rgb(0, 84, 119)); /*Opera */ background: -moz-linear-gradient(tp,rgb(84, 1, 1),rgb(0, 84, 119)); /*Fx */ background: linear-gradient(top, rgb(84, 1, 1),rgb(0, 84, 119)); /*Standard*/ }
Good.image_gradient { background: url('../images/gradient.png'); }
// Animation
Setting Element Position
bobble { 0% { left: 50px; animation-timing-function: ease-in; } 50% { left: 50px; top: 50px; animation-timing-function: ease-out; } 100% { left: 50px; top: 40px; }
bobble { 0% { transform: translate3d(50px, 40px, 0px); animation-timing-function: ease-in; } 50% { transform: translate3d(50px, 50px, 0px); animation-timing-function: ease-out; } 100% { transform: translate3d(50px, 40px, 0px); }
CSS vs. JavaScript
// Garbage Collection
Bad function createElements() { for (var i = 0; i < 100; ++i) { var xBtn = document.createElement('button'); xBtn.setAttribute('value', 'AA'); xBtn.addEventListener('click', hi, false); containerDiv.appendChild(xBtn); xBtn = null; } function clearElements() { containerDiv.innerHTML = ""; }
Good function createElements() { for (var i = 0; i < 100; ++i) { var xBtn = document.createElement('button'); xBtn.setAttribute('value', 'AA'); xBtn.addEventListener('click', hi, false); containerDiv.appendChild(xBtn); xBtn = null; } function clearElements() { var els = containerDiv.childNodes; for (var i = 0; i < els.length; i++) { els[i].removeEventListener('click', hi, false); containerDiv.removeChild(els[i]); }
Minimize Unnecessary Event Listeners
/* bad *//* good */
Let’s say you want to listen to a click event on the elements with the id value of one, two, three, four, and five. Note: They share a common parent with the theDude element!
Bad // ONE FUNCTION FOR EACH EVENT LISTENER for (i = 0; i < 100; i++){ img[i].addEventListener("click", function clickListener(e) { var clickedItem = e.target.id; alert("Hello " + clickedItem); }); }
Good var theParent = document.querySelector("#theDude"); theParent.addEventListener("click", doSomething, false); function doSomething(e) { if (e.target !== e.currentTarget) { var clickedItem = e.target.id; alert("Hello " + clickedItem); } e.stopPropagation(); }
Pay Attention to Memory Leaks
Bad // el is in the global scope, so it persists with the document var el; function doSomething() { el = document.createElement('div'); parent.appendChild(el); } function empty() { parent.innerHTML = ""; }
Good // el is in the local scope, so expires with the function function doSomething() { var el = document.createElement('div'); parent.appendChild(el); } function empty() { parent.innerHTML = ""; }
// UI Controls
“Fast” Clicking
Practical Advice (1/3)
Practical Advice (2/3)
Practical Advice (3/3)