All of the Fasts.

Tree v8 Performance

Tyler Graf

Senior Web Developer familysearch.org

Why Polymer?

Frameworks

(JavaScript)

566KB

132KB

435KB

#useThePlatform

//jquery (28KB)
$('#thing');

//native
document.querySelector('#thing');

//angular 2 (566KB)
this.http.get('/resource')
  .subscribe(data => {
    // do stuff
  });

//native
fetch('/resource')
  .then(res=>res.json)
  .then(data=>{
    // do stuff
  });

Web Components

  • Shadow DOM
  • Custom Elements
  • HTML Templates
  • HTML Imports

SPEC

(specification)

Shadow DOM

Style Encapsulation

Custom Elements

<my-element></my-element>

HTML Templates

<template>
  <header>Title</header>
  <section>
    <p>Hi, I'm inside a template.</p>
  </section>
</template>

HTML Imports

<link rel="import" href="my-element.html">
<link rel="import" href="bower_components/polymer/polymer-element.html">
<link rel="import" href="bower_components/paper-button/paper-button.html">

<dom-module id="my-element">
  <template>
    <style>
      h1 {
        color: red;
      }
    </style>
    
    <h1>Hi</h1>
    <p>[[textContent]]</p>

    <paper-button>Go</paper-button>
  </template>
  
  <script>
    class MyElement extends Polymer.Element {
      static get is() { return 'my-element'; }
      ready() {
        super.ready();
        this.textContent = "I'm a custom element!";
      }
    }

    // Associate the new class with an element name
    customElements.define('my-element', MyElement);
  </script>
</dom-module>

<my-element></my-element>

Support

https://webcomponents.org

Lots or shared components

Cons

  • Not kitchen sink
  • Template bindings
  • polyfills
  • smaller community

Polymer Progression

Polymer 1 - 40KB

Polymer 2 - 12KB

Polymer 3 - ?KB

webcomponents.js (polyfills) - 25KB

HTML Imports => JS Imports

(ES Modules)

Performance

Page Load Times

Metrics

https://speakerdeck.com/addyosmani/the-browser-hackers-guide-to-instant-loading

Goal

Interactive

< 5s

Average Mobile Device over 3G

Phones are slow!

https://speakerdeck.com/addyosmani/the-browser-hackers-guide-to-instant-loading

Current State

Average Web Page on Mobile

16s

Interactive

19s

Fully loaded

420KB

JS

https://www.doubleclickbygoogle.com/articles/mobile-speed-matters/

Test on Real Phones

Chrome Dev Tools

  • Mobile Emulation
  • Remote Device

Safari

  • Remote Debugging

Ask Around for Old Phones

PRPL Pattern

  • Push minimal code for initial route
  • Render the initial route
  • Pre-cache using service worker
  • Lazy load other routes

Code Splitting

Split code up into each route and only load what's needed.

SPA

single page app

https://developers.google.com/web/fundamentals/performance/prpl-pattern/

Case Study

tree v8

Perf Profiles

  • Philippines 3G
    • Australia 3G 1.6Mbps/768Kbps 300ms RTT EC2
  • Wasatch User
    • California Cable 5Mbps/1Mbps 28ms RTT EC2
  • Virginia 3G Mobile
    • Virginia 3G 1.6Mbps/768Kbps 300ms RTT Moto G4
  • Virginia iPhone
    • Virginia LTE 12Mbps/12Mbps 70ms RTT iPhone 6s

Baseline

Philippines 3G - 16.1s

  • CDN
  • Minified
  • gzipped
  • http2
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Title</title>
  </head>
  <body>
    
    <link rel="import" href="my-app.html">

    <link rel="import" href="person-card.html">
    <link rel="import" href="other-thing.html">

    <my-app></my-app>

  </body>
</html>
<link rel="import" href="polymer.html">
<link rel="import" href="app-route.html">
<link rel="import" href="app-location.html">
<link rel="import" href="iron-pages.html">
<link rel="import" href="fs-app-path.html">
<link rel="import" href="tree-behavior.html">
<link rel="import" href="tree-help.html">

index.html

my-app.html

Steps

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Title</title>
  </head>
  <body>
    
    <link rel="import" href="my-app.html">

    <link rel="import" href="person-card.html">
    <link rel="import" href="other-thing.html">
    
    <link rel="import" href="/elements/tree-pwa/tree-app.html">
    <link rel="import" href="/components/polymer/polymer.html">
    <link rel="import" href="/components/app-route/app-route.html">
    <link rel="import" href="/components/app-route/app-location.html">
    <link rel="import" href="/components/iron-location/iron-location.html">
    <link rel="import" href="/components/iron-location/iron-query-params.html">
    <link rel="import" href="/components/app-route/app-route-converter-behavior.html">
    <link rel="import" href="/components/iron-pages/iron-pages.html">
    <link rel="import" href="/components/iron-resizable-behavior/iron-resizable-behavior.html">
    <link rel="import" href="/components/iron-selector/iron-selectable.html">
    <link rel="import" href="/components/iron-selector/iron-selection.html">
    <link rel="import" href="/elements/fs-app-path/fs-app-path.html">
    <link rel="import" href="/elements/tree-pwa/tree-behavior.html">
    <link rel="import" href="/elements/tree-help/tree-help.html">
    <link rel="import" href="/components/wc-i18n/wc-i18n.html">
    <link rel="import" href="/components/fs-help-tray/fs-help-tray.html">
    <link rel="import" href="/components/fs-styles/fs-styles.html">
    <link rel="import" href="/components/fs-styles/dist/base.min.css">
    <link rel="import" href="/components/fs-help-tray/fs-help-tray-styles.html">
    <link rel="import" href="/components/fs-user-service/fs-user-service.html">
    <link rel="import" href="/components/fs-cache/fs-cache.html">
    <link rel="import" href="/components/fs-globals/fs-globals.html">
    
    <link rel="import" href="/elements/tree-pedigree/tree-pedigree.html">
    <link rel="import" href="/components/polymer/polymer.html">
    <link rel="import" href="/components/wc-i18n/wc-i18n.html">
    <link rel="import" href="/components/fs-cache/fs-cache.html">
    <link rel="import" href="/components/fs-globals/fs-globals.html">
    <link rel="import" href="/components/styles-wc/fs-icon-eol/fs-icon-eol.html">
    <link rel="import" href="/elements/tree-pedigree/tree-pedigree-state.html">
    <link rel="import" href="/elements/v8-redux/v8-redux.html">
    <link rel="import" href="/components/polymer-redux/polymer-redux.html">
    <link rel="import" href="/elements/tree-pedigree/pedigree-data-service.html">
    <link rel="import" href="/components/fs-cache/fs-crypto.html">
    <link rel="import" href="/elements/tree-pedigree/Pedigree.html">
    <link rel="import" href="/elements/pedigree-preferences/pedigree-preferences.html">
    <link rel="import" href="/components/oak-ajax-behavior/oak-ajax-behavior.html">
    <link rel="import" href="/components/dialog-el/fs-dialog-eol.html">
    <link rel="import" href="/components/fs-styles/fs-styles.html">
    <link rel="import" href="/components/fs-styles/dist/base.min.css">
    <link rel="import" href="/components/fs-user-service/fs-user-service.html">
    <link rel="import" href="/components/iron-iconset-svg/iron-iconset-svg.html">
    <link rel="import" href="/components/iron-meta/iron-meta.html">
    <link rel="import" href="/components/styles-wc/fs-button-eol/fs-button-eol.html">
    <link rel="import" href="/elements/pedigree-preferences/pedigree-preferences-state.html">
    <link rel="import" href="/components/fs-metrics/fs-metrics.html">
    <link rel="import" href="/elements/pedigree-couple-renderer/pedigree-couple-renderer.html">
    <link rel="import" href="/components/fs-tree-person-renderer/fs-tree-person-renderer.html">
    <link rel="import" href="/components/styles-wc/fs-person-eol/fs-person-eol.html">
    <link rel="import" href="/components/oak-i18n-behavior/oak-i18n-behavior.html">
    <link rel="import" href="/components/fs-person-data-service/fs-person-data-service.html">
    <link rel="import" href="/components/fs-couple-renderer/fs-couple-renderer.html">
    <link rel="import" href="/components/fs-indicators/fs-indicators.html">
    <link rel="import" href="/components/fs-indicators/fs-indicators-service.html">
    <link rel="import" href="/components/fs-indicators/fs-indicators-flyout/fs-indicators-flyout.html">
    <link rel="import" href="/components/birch-inner-html/birch-inner-html.html">
    <link rel="import" href="/components/dialog-el/fs-common-dialog-eol.html">
    <link rel="import" href="/components/styles-wc/fs-alert-message-eol/fs-alert-message-eol.html">
    <link rel="import" href="/components/fs-labelled-link/fs-labelled-link.html">
    <link rel="import" href="/components/styles-wc/fs-badge-eol/fs-badge-eol.html">
    <link rel="import" href="/components/fs-temple/fs-temple-reserve/fs-temple-reserve.html">
    <link rel="import" href="/components/fs-temple/fs-temple-reserve-row/fs-temple-reserve-row.html">
    <link rel="import" href="/components/fs-temple/fs-temple-ordinance-status/fs-temple-ordinance-status.html">
    <link rel="import" href="/components/fs-temple/fs-temple-ordinance-status/ordinance-icon.html">
    <link rel="import" href="/components/fs-permissions/fs-permissions.html">
    <link rel="import" href="/components/fs-temple/fs-temple-request-ordinance-permission/fs-temple-request-ordinance-permission.html">
    <link rel="import" href="/components/iron-pages/iron-pages.html">
    <link rel="import" href="/components/iron-resizable-behavior/iron-resizable-behavior.html">
    <link rel="import" href="/components/iron-selector/iron-selectable.html">
    <link rel="import" href="/components/iron-selector/iron-selection.html">
    <link rel="import" href="/components/fs-inner-html/fs-inner-html.html">
    <link rel="import" href="/components/fs-temple/fs-temple-reserve/fs-temple-reserve-service.html">
    <link rel="import" href="/components/fs-temple/fs-temple-legend/fs-temple-legend.html">
    <link rel="import" href="/components/fs-temple/fs-temple-policy/fs-temple-policy.html">
    <link rel="import" href="/components/fs-temple/fs-temple-icon/fs-temple-icon-service.html">
    <link rel="import" href="/components/fs-temple/fs-temple-icon/fs-temple-icon.html">
    <link rel="import" href="/elements/pedigree-couple-renderer/pedigree-couple-renderer-service.html">
    <link rel="import" href="/elements/booklet-popover/booklet-popover.html">
    <link rel="import" href="/components/app-route/app-route.html">
    <link rel="import" href="/elements/tree-pwa/tree-behavior.html">
    <link rel="import" href="/elements/tree-pedigree/save-state.html">
    <link rel="import" href="/elements/fs-tree-navigation/fs-tree-navigation.html">
    <link rel="import" href="/components/iron-media-query/iron-media-query.html">
    <link rel="import" href="/elements/fs-app-path/fs-app-path.html">
    <link rel="import" href="/components/iron-location/iron-location.html">
    <link rel="import" href="/elements/history-list/history-list.html">
    <link rel="import" href="/components/iron-list/iron-list.html">
    <link rel="import" href="/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
    <link rel="import" href="/components/iron-scroll-target-behavior/iron-scroll-target-behavior.html">
    <link rel="import" href="/components/fs-add-person/fs-add-person.html">
    <link rel="import" href="/components/resettable-properties-behavior/resettable-properties-behavior.html">
    <link rel="import" href="/components/birch-standards-picker/birch-standards-picker.html">
    <link rel="import" href="/components/birch-typeahead/birch-typeahead.html">
    <link rel="import" href="/components/paper-listbox/paper-listbox.html">
    <link rel="import" href="/components/iron-menu-behavior/iron-menu-behavior.html">
    <link rel="import" href="/components/iron-selector/iron-multi-selectable.html">
    <link rel="import" href="/components/paper-styles/default-theme.html">
    <link rel="import" href="/components/paper-styles/color.html">
    <link rel="import" href="/components/paper-item/paper-item.html">
    <link rel="import" href="/components/iron-flex-layout/iron-flex-layout.html">
    <link rel="import" href="/components/paper-item/paper-item-behavior.html">
    <link rel="import" href="/components/iron-behaviors/iron-button-state.html">
    <link rel="import" href="/components/iron-behaviors/iron-control-state.html">
    <link rel="import" href="/components/paper-item/paper-item-shared-styles.html">
    <link rel="import" href="/components/paper-styles/typography.html">
    <link rel="import" href="/components/font-roboto/roboto.html">
    <link rel="import" href="/components/paper-item/paper-item-body.html">
    <link rel="import" href="/components/paper-item/paper-icon-item.html">
    <link rel="import" href="/components/birch-typeahead/birch-typeahead.css">
    <link rel="import" href="/components/paper-menu/paper-menu.html">
    <link rel="import" href="/components/paper-menu/paper-menu-shared-styles.html">
    <link rel="import" href="/components/birch-standards-picker/birch-standards-picker.css">
    <link rel="import" href="/components/fs-add-person/fs-name-template/fs-name-template.html">
    <link rel="import" href="/components/fs-cache/fs-cache-item.html">
    <link rel="import" href="/components/fs-add-person/fs-transliteration-service/fs-transliteration-service.html">
    <link rel="import" href="/components/fs-add-person/fs-search-results-couple/fs-search-results-couple.html">
    <link rel="import" href="/components/fs-life-events/fs-life-events.html">
    <link rel="import" href="/components/fs-add-person/fs-add-person-service/fs-add-person-service.html">
    <link rel="import" href="/components/fs-add-person/fs-person-search-service/fs-person-search-service.html">
    <link rel="import" href="/components/app-route/app-location.html">
    <link rel="import" href="/components/iron-location/iron-query-params.html">
    <link rel="import" href="/components/app-route/app-route-converter-behavior.html">
    <link rel="import" href="/elements/first-run-start/first-run-start.html">

    <my-app></my-app>

  </body>
</html>

index.html

Front-load

Front-load Components

Interactive

16.1 => 14.5s

Async Javascript Loading

fs-cache.html

<link rel="import" href="../polymer/polymer.html">

<script src="../localforage/dist/localforage.nopromises.min.js"></script>
<script src="../localforage-sessionstoragewrapper/src/localforage-sessionstoragewrapper.js"></script>
<script src="../localForage-memoryStorageDriver/dist/localforage-memoryStorageDriver.js"></script>
<script src="./fs-cache.js"></script>

Resource Hints

Title Text

<link rel="dns-prefetch" href="https://fscdn.edge.com">

<link rel="preload" href="/script1.js" as="script">
<link rel="preload" href="/script2.js" as="script">


<link rel="import" href="/my-app.html">





Example

Front-load

Preload javascript

Interactive

Philippines 3G - 16.1 => 14.5 => 10.6s

Support

http://caniuse.com/#search=preload

Streaming

Example

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>

    <link rel="dns-prefetch" href="origin.com">
    
    <link rel="preload" href="script1.js" as="script">
    
    <link rel="import" href="my-app.html">
    <link rel="import" href="my-other.html">
    
  </head>
  <body>
  <!-- person id received from xhr call on server -->
  <my-app person-id="MMMM-MMM"></my-app>
  
</body>
</html>

Server makes xhr call to get data needed on page

1

2

3

Stream Pedigree Data

  <script>
    window.PEDIGREE_DATA = {data: 'data'};
  </script>

  <!-- person id received from xhr call on server -->
  <my-app person-id="MMMM-MMM"></my-app>
  
</body>
</html>

Stream Pedigree Data

Interactive

16.1 => 14.5 => 10.6 => 8.7s

Support

All the browsers forever

http://knowyourmeme.com/

Justifications

Change of measurement

Cold Load

Navigate from homepage

Justifications

Interactive

16.1 => 14.5 => 10.6 => 8.7 => 6.2

Shipment

480 => 846KB

6.2 => 13.6s

On-demand/deferred

<script>
  window.addEventListener('load', function(){

    function importHrefs(hrefs){
      hrefs.forEach(function(href){
        Polymer.Base.importHref(href);
      });
    }

    var links = [
      "<%- resolvePath('/components/dialog-el/fs-common-dialog-eol.html') %>",
      "<%- resolvePath('/elements/tree-help/tree-help.html') %>",
    ];

    importHrefs(links);

  });
</script>

Deferred Loading

(window load event)

_openIndicatorFlyoutEH: function(e){
  e.stopPropagation();

  this.loading = true;

  this.importHref(flyoutHref, function(){
    this.loading = false;
    this._openIndicatorFlyout(evt);
  }.bind(this));

}

On-demand Loading

When user clicks something

Deferred/On-demand

480 => 846 => 420KB

6.2 => 13.6 => 6.4s

Rollup

d3.js

75KB

d3-rollup.js

15KB

Future

H2 Server Push

https://speakerdeck.com/addyosmani/the-browser-hackers-guide-to-instant-loading

Waterfall

https://speakerdeck.com/addyosmani/the-browser-hackers-guide-to-instant-loading

Support

http://caniuse.com/#search=http2

Draw Back

Server doesn't know if asset is cached in browser, so it will always push.

Service Workers

to the rescue

Network Interceptor

Support

http://caniuse.com/#search=serviceworker

Lighthouse

Go and Do!

https://giphy.com

Made with Slides.com