Optimizing JavaScript Runtime Performance for Touch - Velocity 2013

Optimizing JavaScript Runtime Performance for Touch - Velocity 2013

7789780aef9007e64e1ea4af4898e4c4?s=128

Stephen Woods

June 19, 2013
Tweet

Transcript

  1. Optimizing JavaScript Runtime Performance for Touch Stephen Woods @ysaw

  2. Native-Like Experience

  3. Hardware Core OS Core Services Media Cocoa Touch

  4. Hardware Core OS Core Services Media Cocoa Touch WebKit JavaScript

    Runtime WebCore
  5. The Mobile Web is Slow

  6. What Happens at runtime? • Fetch, format and Display Data

    • Handle UI Events • Move Pixels
  7. Fetching Data

  8. None
  9. None
  10. Caching: The cause of, and solution to, all of life's

    problems
  11. $.get('data.json',  dataCallback);

  12. $.get('/data.json',  dataCallback); myDAL.getData('key',  callback);

  13. getData  =  function(key,  callback)  {    if(cache[key])  return  cache[key];  

     $.get('/data.json',  function(data){        cache[key]  =  data;        callback(data);    } } myDAL.getData('key',  callback);
  14. window.localStorage['cache']  =           JSON.stringify(cache);

  15. TTL Writes Invalidate Cache

  16. Eviction www.flickr.com/photos/75397401@N02/ 5mbs of localStorage Strings stored as UTF-16 Characters

    Maximum Storage space: 2.5million Characters
  17. Least Recently Used

  18. None
  19. None
  20. None
  21. None
  22. None
  23. None
  24. Computing the size of the Cache. JSON.stringify(localStorage).length

  25. Handling Events

  26. Event handling is a conversation

  27. If a gesture is in progress, the UI must be

    in motion.
  28. Moving Pixels

  29. 30fps = 33.3ms Per Frame 60fps = 16.6ms Per Frame

  30. None
  31. Write-Only DOM

  32. getOffsetHeight : 74% slower than get className

  33. If you can, cache the value, not the node

  34. None
  35. None
  36. var  offsetCache  =  {}; function  getOffsetHeight(id)  {      

     if(offsetCache[id])  {                return  offsetCache[node.id];        }  else  {                offsetCache[id]  =                          document.getElementById(id).offsetHeight        } }
  37. this.nodePositionMap[thisId]  =  {    top:  thisNode.getY(),    height:  thisNode.get('offsetHeight'),  

     defer:photoList[i].defer  ?  {img_url:  'bar'}:  false };
  38. None
  39. background-­‐image:  'foo.jpg'; background-­‐size:  100%; transform:  translate3d(10,10,1);

  40. None
  41. None
  42. User feedback comes first

  43. isSwiping = 1;

  44. function  handleXHR(resp)  {    if(isSwiping)  {        setTimeout(function(){

                   handleXHR(resp);        },20);    }    processData(desp); }
  45. None
  46. • Load image ~ 300ms (async) • Find Faces ~

    100ms (sync) • Compute Entropy Crop ~ 30ms (sync) • Smooth Animation (sync)
  47. Run Animation in a Separate Thread

  48. slide1.style.transition  =  transitionDuration  +            

                                             's  transform  ease-­‐out'; slide1.style.transform  =  computedEndFrame;
  49. Run Slow Code in a Worker*

  50. Run Slow Code in a Worker* *except on Android Browser

  51. worker  =  new  Worker('/smart-­‐crop-­‐worker.js');

  52. UI Thread Handles Events and Orchestration

  53. • Cache data where possible • Update the UI on

    events, use transforms when possible • Multitask when you can, both with threads and yeilding
  54. flickr.com/photos/39747297@N05/5230479916/ flickr.com/photos/pandameixiang/6784480227/ flickr.com/photos/ryfter/5196109310/ flickr.com/photos/howvin/4054392601/ flickr.com/photos/fdrlibrary/ @ysaw stephenwoods.net touch-interfaces.com flickr.jobs