Responsive Design Sumit Amar Director of Engineering, Electronic Arts.

23
Responsive Design Sumit Amar Director of Engineering, Electronic Arts

Transcript of Responsive Design Sumit Amar Director of Engineering, Electronic Arts.

Responsive Design

Sumit AmarDirector of Engineering, Electronic Arts

Agenda

• Designing for performance• Tools to measure performance• Performance best practices• Memory leaks• Infinite scrolling scenarios• Q&A

Designing for performance

General• Put JavaScript in their own files, and mark them cacheable on

the web server• Add a querystring parameter with your application version

number• Cache, cache, cache! Leverage localStorage (5MB on desktop

and 2.49 on most mobiles)• Use image sprites• Gzip/Deflate stream JavaScript, Images, and CSS files on web

server• Be careful with GIFs. Could leak memory, and they’re

annoying (I think)• Cache XHR calls as well

Designing for performance..contd.

JavaScript• Modularize your JavaScript in object oriented

manner. (Hint: Doug Crockford)• Combine XHR calls if possible• Use WebSockets instead of polling for

persistent like connections– Use SignalR or Socket.IO if you want fallback

support for polling

Designing for performance..contd.

• Be careful about the circular references– Could cause memory leaks– Could add general memory overhead

• Nullify your objects when done with them• Use primitive constructs– for loop instead of for..in loop– arr[arr.length] = ‘..’ instead of arr.push(‘..’)– Direct object properties instead of ‘with’ clause

• Keep reference to often-used objects and reuse them

Designing for performance..contd.• Loading scripts asynchronously

– SCRIPT calls are blocking so use them at the bottom or use DEFER clause– Instead of statically adding SCRIPT tags, consider loading them on-demand

and programmatically. It’s asynchronous but requires special handlinge.g.var loadScript = function(src){script = document.createElement('script'); script.setAttribute('src', src); script.onload = script.onreadstatechange = function() { if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') { {//add script element to the DOM} };}

Designing for performance..contd.

CSS• Use image sprites for icons etc. in CSS• Use CSS gradients, animations and transitions

instead of coding up in JavaScript wherever possible

• Don’t use inline CSS (STYLE attribute or element), to reduce payload size

• Use a framework such as LESS to reuse variables in CSS and use easy hierarchy

• Use multiple classes on elements if needed (increases re-use of classes)

Tools to measure performance

• IE Development tools – Script Profiler, UI Responsiveness, and Memory Profiler (latter two in IE11 only)

• Chrome and Safari development tools for memory profiling.

• Drip / Sieve for memory leak detection in IE• RADAR for any memory leaks detection in

Windows• YSlow for simple performance checks and

recommendations

Demo

• Demo of various tools

Scrolling performance

• Scrolling scenarios – Snap-In vs. Inertial (aka Momentum) Scrolling– Ever-growing memory with images– Optimizing image memory for the viewport

• Discussion – Keeping a memory pool

Outcomes

• Learn about memory profiling tools• Gauge memory utilization and collection• Learn to keep allocated memory in check• Explore future ideas on optimizing further.

Introduction

• Scriptable elements• Challenges in Inertial Scrolling– Blocked UI thread on momentum in iOS– More than required calls for other browsers– Seamless integration of new records (flicker free)

• Why care?– Sluggishness and App crashes!

• Keeping memory in your control (to some extent)

Remedies

• Have a “Load More” button at the bottom– Really?

• Remove elements not seen by user– Challenges:• Easy for Snap-in scenario but not for the inertial• How and when to bring the elements back

• Snap-In experience (page by page swipe)– Ideal for horizontal scroll, but tiring for vertical

Idea 1 – Use a stack

• Track scroll distance (scrollTop) for a container• If there are enough items scrolled-up– Push those elements’ (viz. images) metadata onto a

Stack (a tuple with ID and metadata)– Attempt to remove the element from the DOM– Serialize the stack onto localStorage

• If user scrolls back– Load the stack from localStorage– Pop n items from stack– Reload the element with metadata

Idea 1..contd.

Idea 1 – Using stack works, but:– In a fast scroll or drag scenario, it can miss items– In a far drag scenario, loading all intermediary

elements is sub-optimal because they’re not being seen anyway

Sample structure[[“h1”,”http://localhost/a.jpg”], [“h2”,”http://localhost/b.jpg”]]

Idea 2 – Range hash table

• Track scroll distance (scrollTop) for a container• If there are enough items scrolled-up– Grab offsetTop of n items sequentially– Determine a ‘range’ where this pixel position lies• E.g. item on 2560 will be between 2000-3000

– Create a pair with key being the element ID and value being the metadata such as image URL

– Store the pair in the range key created– Serialize the hash table onto localStorage

Idea 2 – Range hash table..contd

• If the user scrolls or drags quickly back up– Grab scrollTop position of container– Determine a ‘range’ where this pixel position lies• E.g. being at pixel 2560 will be between 2000-3000

– Load items from 2000-3000, and 1k-2k + 3k-4k ranges, and add them back to DOM

– Delete restored keys from respective ranges– Serialize the modified hash table onto localStorage

Idea 2 – Contd.Idea 2 – Using a range hash table works, but:

– Inefficient for minor scrolls

Sample structure:{“0-1000”:

{ “h1”:”http://localhost/a.jpg”, “h2”:http://localhost/b.jpg},

“1000-2000”: { “h3” :http://localhost/c.jpg } }

Idea 1 + Idea 2

• Track scroll distance (scrollTop) for a container• If there are enough items scrolled-up– Grab offsetTop of n items sequentially– Determine a ‘range’ where this pixel position lies

• E.g. item on 2560 will be between 2000-3000

– Create a pair with key being the element ID and value being the metadata such as image URL

– Create a tuple containing ID and metadata– Push tuple onto stack– Store the pair in the range key created– Serialize hash table and stack to localStorage

Idea 1 + Idea 2

• When user backs up– Grab scrollTop of container– Load from stack, and delete corresponding key

from the Range hash table– If a large distance between last two scroll

positions found:• Load from Range hash table, delete the loaded item’s

key

• DEMO at http://www.amar.co.in/view.html

Issues – Future ideas• Loading an item from Hashtable-only, doesn’t

remove from stack because O(n) would be suboptimal

• Scrolling down, and then up restores items, but doesn’t remove items from the bottom of the container

• Pooling and Recycling of DOM elements – The infinite scrolling scenarios can be addressed by using a finite set of elements and translate3d, but requires implementing inertia in JS (no Hard Acceleration)

Summary

• Keep an eye on increasing memory• Try to remove memory allocated to elements

not seen by user• Inertial scrolling preferred in vertical scrolls,

but challenging to optimize• Further optimizations

Questions ?

Contact/Suggestions - [email protected] source Code - www.amar.co.in/code/memory.zip Slide deck – www.amar.co.in/ppt/devcon5responsive.pptx