Share
Embed
Escaping the uncanny valley (Velocity 2013)
Techniques for matching native app performance on the web with HTML5 (updated for Velocity 2013, Santa Clara
Andrew Betts
June 19, 2013
Transcript
64 slides
-
Escaping the uncanny valley Techniques for matching native app performance
on the eb ith HTML5 ndre Betts (@triblondon) Director, FT Labs (@ftlabs) -
The uncanny valley Visual similarity to humans Emo0onal
response to a robot A"rac&on Repulsion None Iden&cal -
1880 1900 1920 1940 1960 1980 2000 2020 e’ve been
doing this for a hile. -
orks offline Portable Long battery life Can be read in
bright sunlight Cheap Ubiquitous Bookmarkable Sharable Nesprint Fast start up Supports clipping/saving Can be read in the dark Updates in real time Electronic delivery Search Personalisation Deep linking -
e need to care about supporting existing features as much
as getting ne ones. -
Lose the constraints • Tablet • Phone • Desktop •
Laptop • TV • Games console • In car screen • In flight screen • Billboard • Kiosk • e-ink reader • Hot air balloon -
The FT eb app… The FT eb app provides a
touch optimised user experience ithout native code. -
The Economist n HTML5 ebsite rapped in native containers for
BlackBerry, indos and Chome -
The basics Learn ho the broser optimises stuff: the easy
ay is not alays the fastest ay. -
Hover effects • Disable hover effects on non-hoverable devices and
during scrolls .hoverable a:hover { ... } <body class='hoverable'> ... </body> -
Storing data HTML5 can store data on device too, it's
just… ell, it's complicated. -
happy family of technologies • ebSQL • IndexedDB •
localStorage (and sessionStorage) • Cookies • HTML5 pplication Cache • FilePI -
localStorage vs indexedDB 242 296 175 259
6873 29897 1 10 100 1000 10000 100000 IDB Large IDB Small ebSQL Large ebSQL Small localStor Large localStor Small Operations per second (more is better) h@p://jsperf.com/indexeddb-‐vs-‐localstorage/13 -
HTML5 application cache • lays caches parent page • lays
serves from cache, even hen connected • Cannot add or remove anything ithout repopulating entire cache • Treats cache-control headers differently in different brosers • Fallbacks block on default broser netork timeout (probably a minute or so) -
• Redefine appcache syntax • Still mostly declarative • Sub-manifests:
multiple atomic groups • JS PI to bring transparency • eb orker option for advanced usage • Pattern matching fallbacks • Remove the ‘magic’, like auto- adding masters • Ditch appcache, define ne PI • lmost entirely imperative • Individual atomic cache groups accessed via PIs • Install a controller to intercept and route requests • “Bring your on unicorn” -
Current best practice • Use appcache sparingly – Fonts, sprites, one
master, and a fallback entry – CSS, HTML, JS in localStorage – Other approaches: see Jake rchibald • localStorage for speed • Database for capacity -
Storage optimisation hile e are limited by tiny quotas, e
need to learn to live ith less. -
Text encoding ‘compression’ • JavaScript internally uses UTF-16 for text
encoding • Great idea for processing: fast string operations, full support for Unicode BMP • Terrible idea for storage of English text or base-64 encoded images. -
Squeeze your bits Text S i m
p l e Decimal 83 105 109 112 108 101 As binary 01010011 01101001 01101101 01110000 01101100 01100101 ShiOed 01010011 01101001 01101101 01110000 01101100 01100101 As hex 53 69 6D 70 6C 65 UTF-‐16 卩 浰 汥 -
SCII packed into UTF-16 function compress(s) { var i,
l, out=''; if (s.length % 2 !== 0) s += ' '; for (i = 0, l = s.length; i < l; i+=2) { out += String.fromCharCode((s.charCodeAt(i)<<8) + s.charCodeAt(i+1)); } return out; } -
Decompressing function decompress_v1(data) { var i, l, n, m,
out = ''; for (i = 0, l = data.length; i < l; i++) { n = data.charCodeAt(i); m = Math.floor(n / 256); out += String.fromCharCode(m) + String.fromCharCode(n % 256); } return out; } -
function decompress_v14(data) { var i, l, n1, n2, n3,
n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, out = '', getChar = String.fromCharCode; for (i = 0, l = data.length >> 4 << 4; i < l; i++) { n1 = data.charCodeAt(i); n2 = data.charCodeAt(++i); n3 = data.charCodeAt(++i); n4 = data.charCodeAt(++i); n5 = data.charCodeAt(++i); n6 = data.charCodeAt(++i); n7 = data.charCodeAt(++i); n8 = data.charCodeAt(++i); n9 = data.charCodeAt(++i); n10 = data.charCodeAt(++i); n11 = data.charCodeAt(++i); n12 = data.charCodeAt(++i); n13 = data.charCodeAt(++i); n14 = data.charCodeAt(++i); n15 = data.charCodeAt(++i); n16 = data.charCodeAt(++i); out += getChar( n1 >> 8, n1 & 255, n2 >> 8, n2 & 255, n3 >> 8, n3 & 255, n4 >> 8, n4 & 255, n5 >> 8, n5 & 255, n6 >> 8, n6 & 255, n7 >> 8, n7 & 255, n8 >> 8, n8 & 255, n9 >> 8, n9 & 255, n10 >> 8, n10 & 255, n11 >> 8, n11 & 255, n12 >> 8, n12 & 255, n13 >> 8, n13 & 255, n14 >> 8, n14 & 255, n15 >> 8, n15 & 255, n16 >> 8, n16 & 255 ); } for (l = data.length; i < l; i++) { n1 = data.charCodeAt(i); out += getChar(n1 >> 8) + getChar(n1 & 255); } return out; } -
Cache layers Every type of cache offers different trade offs.
So use them all. -
DOM Memory Cache servers Broser storage pplication caching Database Hide/sho
elements already in DOM Instant – paint only. High memory footprint JavaScript variables Very quick – DOM rite + paint. ebSQL/IndexedDB or localStorage I/O on localStorage very fast. DB much sloer but async kamai / Edgecast / Cloudfront etc Fast HTTP delay, fast read from cache, larger storage Memcache pplication overhead, added flexibility, smaller components, MySQL / PostgreSQL / Couch / Mongo etc Ultimate master repository Edge cache (CDN) Varnish / Squid etc Longer HTTP delay, fast read from cache, infinite storage -
Tradeoffs Example render latency (3G network) Effec&ve
capacity DOM 2ms (paint) A few hundred nodes JavaScript memory 10ms (layout + paint) 5MB Browser storage 70ms (read + layout + paint) 50MB Network cache 300ms (network + layout + paint) Infinite Memcache/DB 400ms (backend + network + layout + paint) Infinite -
Netork HTTP requests are painful, so do feer of them
and make them count. -
Latency by radio state Chrome, MacOS, Velocity venue
wifi Safari, iOS, T-‐Mobile EDGE 1s intervals 180ms 850ms 10s intervals 180ms 1,500ms 20s intervals 180ms 2,100ms Try it: h@p://jsfiddle.net/sktbb/6/ Mean round trip 0me from by connec0on type and request interval (50 requests) -
Batch the suckers • ggressive batching - collect requests asynchronously:
• Callbacks per action and per group • Process queues in the background api.add('getStory', {'path': '/1'}, callback1); api.add('getStory', {'path': '/1'}, callback2); api.send(callback3); api.add('healthcheck', params, callback4); api.send(callback5); -
HTTP 2.0 / SPDY • Makes this unnecessary – in
theory • lso see 3C Beacon PI for analytics • Still use cases for delayed requests: – Offline persistence of queued requests -
Using accelerated animation • Repositioning elements causes a relayout •
ccelerated animation = paint only • First: turn on acceleration • Then: apply a transition or animation .thing { -webkit-transform: translateZ(0); } .thing { -webkit-transition: all 3s ease-out; } .thing.left { -webkit-transform: translate3D(0px,0,0); } .thing.right { -webkit-transform: translate3D(600px,0,0); } -
Click delay Native apps react instantly. Use smart touch to
click conversion to keep up -
Fastclick • github.com/ftlabs/fastclick • Removes 300ms delay on touch •
Programmatic clicks aren't quite the same - e handle it here e can (eg apply focus) -
Progress feedback psychology • Providing feedback makes things faster •
Overestimating the time remaining makes it go quicker • Progress feedback that starts earlier finishes sooner -
Thanks andre@labs.ft.com @triblondon, @FTLabs Do you ant to build this
stuff? Join in. [email protected] Image credits:: h@p://cdn3.worldcarfans.co/2008/2/medium/9080214.017.Mini1L.jpg, h@p://www.netbasic.com/blog/2008/10/mini-‐car-‐parking-‐fail, h@p://runningstopsigns.files.wordpress.com/ 2011/04/smart-‐car.jpg -
Handpicked attendees dvanced topics Unique format Engaging and collaborative Presented
by the FT and Google Register to participate at edgeconf.com