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

Polymer Performance Patterns

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.
Avatar for Eric Bidelman Eric Bidelman
September 15, 2015

Polymer Performance Patterns

Polymer Summit 2016 presentation. Tips, tricks, patterns for building faster Polymer and web component-based apps.

Video: https://www.youtube.com/watch?v=Yr84DpNaMfk

Avatar for Eric Bidelman

Eric Bidelman

September 15, 2015
Tweet

More Decks by Eric Bidelman

Other Decks in Technology

Transcript

  1. @ebidel @polymer #polymersummit optimizing load & first paint LOAD optimization

    tips for minimizing in-app jank RENDER future APIs for performance FUTURE
  2. the extent to which an investment is profitable, especially in

    relation to other investments. PERFORMANCE noun -
  3. the extent to which an investment is profitable, especially in

    relation to other investments. PERFORMANCE noun -
  4. the extent to which an investment is profitable, especially in

    relation to other investments. PERFORMANCE noun - app apps usable
  5. DELAY USER REACTION 0 - 100 ms Instant 100 -

    300 ms Slight perceptable delay 300 - 1000 ms Task focus, perceptable delay 1000+ ms Mental context swtich 10,000+ ms I’ll come back later! User perception-reaction times http://goo.gl/7noSwL
  6. 0 150 300 450 600 Time 3x faster CHROME 0

    750 1500 2250 3000 Time 4x faster iOS SAFARI
  7. <html> <head> </head> <body ... </body> </html> <link rel="import" href="elements.html">

    HTML Imports do not block parsing but they do block page rendering.
  8. <html> <head> </head> <body ... </body> </html> <link rel="import" href="elements.html"

    async> Make it async if you don’t want to block rendering.
  9. Dynamically load an HTML Import function importPage(url) { return new

    Promise(function(resolve, reject) { resolve(e.target.import); }, reject); }); }; Polymer.Base.importHref(url, function(e) { importPage(‘/path/to/import.html’).then(doStuff);
  10. Dynamically load an HTML Import function resolve }; Dynamically creates

    and loads <link rel=“import” href=“/path/to/ import.html”> Polymer.Base.importHref(url, function(e) { importPage
  11. Dynamically load an HTML Import function importPage(url) { return new

    Promise(function(resolve, reject) { resolve(e.target.import); }, reject); }); }; Dynamically creates and loads <link rel=“import” href=“/path/to/ import.html”> Polymer.Base.importHref(url, function(e) { importPage(‘/path/to/import.html’).then(doStuff);
  12. <html> <head> <script src="webcomponents-lite.min.js" async></script> </head> <body unresolved> <paper-drawer-panel> ...

    </paper-drawer-panel> </body> </html> Declarative imports load faster <link rel="import" href="elements.html" async>
  13. <html> <head> </head> <body ... </body> </html> Declarative imports load

    faster <link rel="import" href="elements.html" async>
  14. <html> <head> <script src="webcomponents-lite.min.js" async></script> <link rel="import" href="elements.html" async> </head>

    <body> <paper-drawer-panel> ... </paper-drawer-panel> </body> </html> “Fast load skeleton” Async all the things. Control FOUC ourselves!
  15. <html> <head> <link rel="import" href="elements.html" async> </head> <body> <paper-drawer-panel> ...

    </paper-drawer-panel> </body> </html> <script src="webcomponents-lite.min.js" async></script>
  16. <html> <head> <link rel="import" href="elements.html" async> </head> <body> <paper-drawer-panel> ...

    </paper-drawer-panel> </body> </html> <script src=“app.js" async></script>
  17. var webComponentsSupported = ( 'registerElement' in document && 'import' in

    document.createElement('link') && 'content' in document.createElement('template')); Lazy load the web component polyfills
  18. var webComponentsSupported = ( 'registerElement' in document && 'import' in

    document.createElement('link') && 'content' in document.createElement('template')); if (!webComponentsSupported) { var script = document.createElement('script'); script.async = true; script.src = 'webcomponents-lite.min.js'; script.onload = finishLazyLoading; document.head.appendChild(script); } else { finishLazyLoading(); } Lazy load the web component polyfills
  19. ( DevTools emulation - Good 3G ) 1430ms first paint

    230ms first paint 6.2x faster OLD NEW Stock Ticker App
  20. ( DevTools emulation - Good 3G ) 1430ms first paint

    230ms first paint 6.2x faster OLD NEW Stock Ticker App
  21. <html> <head> </head> <paper-drawer-panel> ... </paper-drawer-panel> </body> </html> <body> <!--

    removed unresolved attr. --> <link rel="import" href="elements.html" async>
  22. <html> <head> </head> ... </body> </html> <body> <!-- removed unresolved

    attr. --> <link rel="import" href="elements.html" async>
  23. <html> <head> <link rel="import" href="elements.html" async> <style> paper-header-panel[drawer]:unresolved { display:

    none; } paper-toolbar.tall:unresolved { height: 192px; background: #42A5F5; } </style> </head> <body> <paper-drawer-panel> <paper-header-panel drawer>...</paper-header-panel> <paper-header-panel mode="cover" main> <paper-toolbar class="tall"> ... </paper-toolbar> </paper-header-panel> </paper-drawer-panel> </body> </html>
  24. <html> <head> <link rel="import" href="elements.html" async> <style> paper-header-panel[drawer]:unresolved { display:

    none; } paper-toolbar.tall:unresolved { height: 192px; background: #42A5F5; } </style> </head> <body> <paper-drawer-panel> <paper-header-panel drawer>...</paper-header-panel> <paper-header-panel mode="cover" main> <paper-toolbar class="tall"> ... </paper-toolbar> </paper-header-panel> </paper-drawer-panel> </body> </html>
  25. <html> <head> <link rel="import" href="elements.html" async> <style> paper-header-panel[drawer]:unresolved { display:

    none; } paper-toolbar.tall:unresolved { height: 192px; background: #42A5F5; } </style> </head> <body> <paper-drawer-panel> <paper-header-panel drawer>...</paper-header-panel> <paper-header-panel mode="cover" main> <paper-toolbar class="tall"> ... </paper-toolbar> </paper-header-panel> </paper-drawer-panel> </body> </html>
  26. <html> <head> <link rel="import" href="elements.html" async> <style> paper-header-panel[drawer]:unresolved { display:

    none; } paper-toolbar.tall:unresolved { height: 192px; background: #42A5F5; } </style> </head> <body> <paper-drawer-panel> <paper-header-panel drawer>...</paper-header-panel> <paper-header-panel mode="cover" main> <paper-toolbar class="tall"> ... </paper-toolbar> </paper-header-panel> </paper-drawer-panel> </body> </html>
  27. <html> <head> <link rel="import" href="elements.html" async> <style> paper-header-panel[drawer]:unresolved { display:

    none; } paper-toolbar.tall:unresolved { height: 192px; background: #42A5F5; } </style> </head> <body> <paper-drawer-panel> <paper-header-panel drawer>...</paper-header-panel> <paper-header-panel mode="cover" main> <paper-toolbar class="tall"> ... </paper-toolbar> </paper-header-panel> </paper-drawer-panel> </body> </html>
  28. @ebidel @polymer #polymersummit PolyMail 1.0 ‣ ES6 classes ‣ Async

    Imports, lazy loaded polyfills ‣ Add to Homescreen ‣ <meta name="theme-color"> ‣ Offline Source: github.com/ebidel/polymer-gmail poly-mail.appspot.com
  29. @ebidel @polymer #polymersummit PolyMail 1.0 ‣ ES6 classes ‣ Async

    Imports, lazy loaded polyfills ‣ Add to Homescreen ‣ <meta name="theme-color"> ‣ Offline Source: github.com/ebidel/polymer-gmail poly-mail.appspot.com
  30. 1144 speed index Cable connection ( DESKTOP ) webpagetest.org results:

    https://goo.gl/LY0sxj 589ms first paint 1s total load
  31. 3G Fast connection ( MOTO G ) 1.66s first paint

    webpagetest.org results: https://goo.gl/LY0sxj
  32. 3G Fast connection ( MOTO G ) 1.66s first paint

    ~ 7s total load webpagetest.org results: https://goo.gl/LY0sxj
  33. 3G Fast connection ( MOTO G ) 5614 speed index

    1.66s first paint ~ 7s total load webpagetest.org results: https://goo.gl/LY0sxj
  34. @ebidel @polymer #polymersummit Changes for fast load 1.Make HTML Imports

    2.Conditionally load the polyfills (or make 3.Manually control FOUC instead of using 4.Load critical “app shell”
  35. <script> window.Polymer = window.Polymer || {dom: ‘shadow'}; </script> <link rel="import"

    href="polymer.html"> Use native shadow DOM ( it’s faster )
  36. Yo, don’t jank those ripples <paper-button raised on-transitionend="_doNav"> <a href="/new"

    on-tap="_navAfterRipple">Add a new feature</a> </paper-button> <script> Polymer({ _navAfterRipple: function(e) { e.preventDefault(); this._href = Polymer.dom(e).localTarget.href; // save reference } _doNav: function(e) { var href = this._href; if (href) { this._href = null; // clear location.href = href; } } }); </script> Ripple jank on page navigations
  37. Yo, don’t jank those ripples <paper-button raised on-transitionend="_doNav"> <a href="/new"

    on-tap="_navAfterRipple">Add a new feature</a> </paper-button> <script> Polymer({ _navAfterRipple: function(e) { e.preventDefault(); this._href = Polymer.dom(e).localTarget.href; // save reference } _doNav: function(e) { var href = this._href; if (href) { this._href = null; // clear location.href = href; } } }); </script> Ripple jank on page navigations
  38. <style> my-element[selected] { border: 1px solid black; } </style> <my-element

    selected></my-element> properties: { selected: { type: Boolean, reflectToAttribute: true } } Minimize property reflection Use only for CSS selectors:
  39. @ebidel @polymer #polymersummit How DOM nodes do modern apps create?

    APP # NODES AT PAGE LOAD Maps 624 Contacts 713 Inbox 988 Calendar 968 Photos 1,106 Github 1,276 G+ 2,838 GMail 2,890
  40. Preload an Import <link rel="preload" href=“/path/to/import.html" as=“html”> Declarative var l

    = document.createElement('link'); l.rel = 'preload'; l.as = 'html'; l.href = '/path/to/import.html'; document.head.appendChild(l); Script preload what you’ll use HTTP header Link: </path/to/>; rel=preload; as=html
  41. @ebidel @polymer #polymersummit Polydev Chrome extension know the costs of

    your elements goo.gl/pgPeCE source: github.com/polymerlabs/polydev
  42. @ebidel @polymer #polymersummit Polymer perf bookmarklet know your app’s metrics

    ‣ Time to first paint & page load ‣ HTML Import load times ( main page ) ‣ # of custom element instances ‣ Element properties using goo.gl/vkJHWm