Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Life on the Grid

Ab098775ed30da167fa4989980c1e2d5?s=47 Matt
March 16, 2014

Life on the Grid

Recording performance, code practices and addressing the unique concerns of image heavy user interfaces like the Netflix clients.

Ab098775ed30da167fa4989980c1e2d5?s=128

Matt

March 16, 2014
Tweet

Transcript

  1. Life on the Grid Addressing scale & performance of a

    large JavaScript application ! @innerhtml / mseeley@netflix.com March 15 & 16, 2014 JQUERY.TO();
  2. 1999

  3. 2006

  4. 2008 - 2009

  5. 2010

  6. 2011 - 2012

  7. 2013+

  8. Android tablets, Apple iPad 2+, Blu-ray players, Televisions, Virgin Media

    TiVo boxes Connected devices Media streamers Nintendo Wii, Nintendo Wii U, PlayStation 3, PlayStation 4, PlayStation Vita, Xbox 360 Game Consoles Apple TV, Google Chromecast, Roku 3, etc…
  9. None
  10. None
  11. HD Full HD Ultra HD Ultra HD has 9x more

    pixels than HD
  12. HD Full HD Ultra HD Ultra HD has 9x more

    elephants than HD
  13. • avoiding surprise • adapting for existing solutions • understanding

    the big picture Surviving a life on the grid is:
  14. Anticipate

  15. Hello existing solution

  16. Hello existing solution

  17. console.timeStamp('Hello world'); ! // ... "children": [{ "startTime": 13939 "type":

    "TimeStamp "data": { "message": "He }, "frameId": "11284. "usedHeapSize": 17 "counters": { "documents": 1 "nodes": 4, "jsEventListen } }] // ...
  18. amp('Hello world'); ! // ... "children": [{ "startTime": 1393965312322.3394, "type":

    "TimeStamp", "data": { "message": "Hello world" }, "frameId": "11284.1", "usedHeapSize": 1758128, "counters": { "documents": 1, "nodes": 4, "jsEventListeners": 0 } }] // ... { "type": "TimeSta "startTime": 139 "endTime": 13939 "data": { "message": " } }
  19. 93965312322.3394, amp", "Hello world" 84.1", 1758128, : 1, teners": 0

    { "type": "TimeStamp", "startTime": 1393965312322.3394, "endTime": 1393965312322.3394, "data": { "message": "Hello world" } }
  20. var timeline = new Timeline(), startup = timeline.mark('Startup'); ! //

    Mark startup began. startup.begin(); ! // ... heigh-ho, heigh-ho. Mark more Tasks. ! // Mark startup ended. Record results. startup.end(); $.post(‘https://...', timeline.data). fail(function () { // Uh-oh! }); Source: https://gist.github.com/mseeley/9570215
  21. 0 1.00s 2.00s 3.00s RECORDS Startup Task A Task B

    Task C Task D Detailed session-level data
  22. 0 1.00s 2.00s 3.00s Task A Task B Task C

    Task D Aggregate task comparisons
  23. Speak for the Code

  24. Async? Sync? Both! var cache = {}, getValue = function

    (url, callback) { if (url in cache) { callback(cache[url]); } else { $.get(url, function(data) { cache[url] = data; callback(data); }); } };
  25. Async once, async always! var cache = {}, getValue =

    function (url, callback) { var complete = function (data) { cache[url] = data; callback(data); }; ! if (url in cache) { setTimeout(complete, 0, cache[url]); } else { $.get(url, complete); } };
  26. myView.show();

  27. myView.show(true);

  28. myView.show(true, 50, ’linear’, 100); actually show? delay? ? slide in?

  29. myView.show(true, 50, ’linear’, 100); actually show? delay? ? slide in?

  30. myView.show(true, 50, ’linear’, 100); actually show? delay? ? slide in?

  31. myView.show(true, 50, ’linear’, 100); actually show? delay? ? slide in?

  32. myView.show(true, 50, ’linear’, 100); actually show? delay? ? slide in?

  33. myView.show({ duration: 50, ease: 'linear', onDone: function () { //

    animation complete! } }); Build forward compatible interfaces
  34. // FIXME: This stinks. ! // TODO: Make this better.

  35. // FIXME: whaa-whaa-whaa ! // TODO: whaa-whaa-whaa

  36. // FIXME comments should provide // context and be actionable.

    // Otherwise they’re code smell.
  37. Take only essentials

  38. • is more than log statements • changes default application

    behavior • may adversely affect performance • will adversely affect file-size Debug code…
  39. if (location.hostname === 'production.com') { // change behavior }

  40. var log = (location.hostname === 'production.com') ? function () {}

    : function () { console.log.apply(console.log, arguments); } };
  41. (function(global){ var prod = location.hostname === 'production.com', api = ["log","debug","info","warn","error","assert","dir","dirxml",

    "trace","group","groupCollapsed","groupEnd","time","timeEnd", "profile","profileEnd","count","exception","table"], log, i, len ; ! if (typeof global.console == "undefined" || !global.console) { try { global.console = {}; } catch (err) { } } ! log = (!prod && typeof global.console.log != "undefined") ? global.console.log : function(){} ; ! for (i=0, len=api.length; i<len; i++) {
  42. sed 's/console.\(log\|debug\|info\|warn\|error\| assert\|dir\|dirxml\|trace\|group\|groupEnd\|time \|timeEnd\|profile\|profileEnd\|count\)(.*);\?//g'

  43. (function(global){ var prod = location.hostname === 'production.com', api = ["log","debug","info","warn","error","assert","dir","dirxml",

    "trace","group","groupCollapsed","groupEnd","time","timeEnd", "profile","profileEnd","count","exception","table"], log, i, len ; ! if (typeof global.console == "undefined" || !global.console) { try { global.console = {}; } catch (err) { } } ! log = (!prod && typeof global.console.log != "undefined") ? global.console.log : function(){} ; ! for (i=0, len=api.length; i<len; i++) { sed 's/console.\(log\|debug\|info\|warn\|error\| assert\|dir\|dirxml\|trace\|group\|groupEnd\|time \|timeEnd\|profile\|profileEnd\|count\)(.*);\?//g' var log = (location.hostname === 'production.com') ? function () {} : function () { console.log.apply(console.log, arguments); } }; if (location.hostname === 'production.com') { // change behavior }
  44. var maxLists = model.maxLists; ! // #ifdef DEBUG if (URL_PARAMS.maxLists)

    { maxLists = URL_PARAMS.maxLists; console.log('Override maxLists’); } // #endif
  45. var groceries = { squash: 2, apples: 8 // #ifdef

    RUGBYSEVENS ,hardCider: 12 ,munchies: 2 // #endif };
  46. 185KB (that’s more than jQuery 1.110 and jQuery 2.1.0 combined)

    Removing debug code saved: See: https://www.npmjs.org/package/preprocessor
  47. Slay dragons

  48. Meet our dragon: displaying lists of lists of video stuff

  49. Initialize everything. How does Webkit do?

  50. Tiles intersecting the viewport Pre-painted to cover scrolling TiledBackingStore See:

    https://trac.webkit.org/browser/trunk/Source/WebCore/ platform/graphics/TiledBackingStore.cpp
  51. The flashes of gray make more sense now, right?

  52. The do it our !&#@ selves approach.

  53. Populated elements intersecting the viewport Elements reduced to placeholders Postponed

    activity See: https://www.w3.org/Bugs/Public/show_bug.cgi?id=20246 https://www.w3.org/Bugs/Public/show_bug.cgi?id=17842
  54. Seek unusual solutions

  55. What’s the best way to preload a bunch of movie

    posters without introducing jank?
  56. Loading Scripting Painting

  57. var xhr = new XMLHttpRequest(), remaining = imgs.length, onload =

    function () { --remaining; if (remaining === 0) { // done! } else if (remaining > 0) { work(); } }, work = function () { xhr.open('GET', imgs.pop(), true); xhr.send(); }; ! xhr.onload = onload; xhr.responseType = 'blob'; ! work();
  58. <script id="imgloader" type="javascript/worker"> // JavaScript from XHR example and an

    onmessage handler </script> <script> var url = URL.createObjectURL( new Blob( [document.getElementById('imgloader').textContent], { type: 'text/javascript' } ) ), worker = new Worker(url); ! worker.onmessage = function () { URL.revokeObjectURL(url); // done! }; ! worker.postMessage(imgs); </script>
  59. None
  60. Tight 60fps frames! Too much scripting & gaps Too much

    scripting & painting & gaps
  61. JavaScript IS a profession @innerhtml / mseeley@netflix.com Thank You! Further

    reading: http://techblog.netflix.com/2013/12/pioneering-application-design-on-tvs-tv.html http://techblog.netflix.com/2012/01/webkit-in-your-living-room.html http://jobs.netflix.com/
  62. JavaScript IS @innerhtml / mseeley@netflix.com Thank You! Further reading: http://techblog.netflix.com/2013/12/pioneering-application-design-on-tvs-tv.html

    http://techblog.netflix.com/2012/01/webkit-in-your-living-room.html http://jobs.netflix.com/