KEMBAR78
High Performance Snippets | PPTX
High Performance
Snippets



        stevesouders.com/docs/fluent-snippets-20120530.pptx
      Disclaimer: This content does not necessarily reflect the opinions of my employer.
synchronous scripts block
all following elements
from rendering
in all browsers
async


#fail
async

           sync

   async
Frontend
 SPOF
http://www.webpagetest.org/result/120529_41_HWV/
http://blog.patrickmeenan.com/2011/10/testing-for-frontend-spof.html
/etc/hosts:
72.66.115.13 apis.google.com
72.66.115.13 www.google-analytics.com
72.66.115.13 static.ak.fbcdn.net
72.66.115.13 connect.facebook.net
72.66.115.13 platform.twitter.com
72.66.115.13 widgets.twimg.com


WebPagetest:
setDnsName apis.google.com blackhole.webpagetest.org
setDnsName www.google-analytics.com blackhole.webpagetest.org
setDnsName static.ak.fbcdn.net blackhole.webpagetest.org
setDnsName connect.facebook.net blackhole.webpagetest.org
setDnsName platform.twitter.com blackhole.webpagetest.org
setDnsName widgets.twimg.com blackhole.webpagetest.org
navigate http://www.businessinsider.com/
original snippet
<script src="http://widgets.twimg.com/j/2/widget.js">
</script>
<script>
new TWTR.Widget({
  version: 2,
  type: 'profile',
  ...
}).render().setUser('souders').start();
</script>
<script>                           asyncified snippet
function doTwitter() {
  if ( this.readyState && this.readyState != "complete"
       && this.readyState != "loaded" ) {
    return;
  }
  this.onload = this.onreadystatechange = null;
  new TWTR.Widget({
    version: 2,
    type: 'profile',
    ...
  }).render().setUser('souders').start();
}
var ts = document.createElement("script");
ts.async = true;
ts.onload = ts.onreadystatechange = doTwitter;
ts.src = "http://widgets.twimg.com/j/2/widget.js";
var s0 = document.getElementsByTagName('script')[0];
s0.parentNode.insertBefore(ts, s0);
</script>
But... you can’t make a script async if it does
 document.write

widget.js does document.write:
init: function(x) {
  ...
  this.id = x.id || "twtr-widget-" + this._widgetNumber;
  if (!x.id) {
    document.write('<div class="twtr-widget" id="' +
                 this.id + '"></div>')
  }
}


What if we create the DIV and specify the id?
asyncified snippet plus DIV
<div class=‘twtr-widget’ id=‘souderstwitter’></div>
<script>
function doTwitter() {
  if ( this.readyState && this.readyState != "complete"
       && this.readyState != "loaded" ) {
    return;
  }
  this.onload = this.onreadystatechange = null;
  new TWTR.Widget({
    id: ‘souderstwitter’,
    version: 2,
    type: 'profile',
    ...
  }).render().setUser('souders').start();
}
var ts = document.createElement("script");
ts.async = true;
...
before
after
While placing JavaScript files at the bottom of the
page is a best practice for website performance,
when including the anywhere.js file, always place
the file as close to the top of the page as possible.
The anywhere.js file is small (<3KB) and is delivered
to the page GZIP'd.
Further, all dependancies for @Anywhere features
are loaded asynchronously, on-demand so as to not
impact performance of the host page.
three facts:
 1. failures happen
 2. 304 & 200 both produce
    frontend SPOF
 3. anywhere.js expires after
    15 minutes
snippet cache times
http://platform.twitter.com/widgets.js - 30 mins
http://connect.facebook.net/en_US/all.js - 15 mins
http://www.google-analytics.com/ga.js - 120 mins
“bootstrap scripts” often have short
 cache times
more frequent Conditional GET requests
 means frontend SPOF is more likely
but short cache times is the only way
 snippet owners can push updates
or is it?
self-updating bootstrap scripts




stevesouders.com/blog/2012/05/22/self-updating-scripts/
part 1: update notification
piggyback on dynamic request
pass cached version # to
 server: ?v=127
server returns:
 204 – no update
 JS – new version available
part 2: overwrite cache
re-request dynamically
rev the URL (querystring)
XHR w/ setRequestHeader
reload iframe containing
 bootstrap script
example
 load bootstrap script:
 var s1=document.createElement('script');
 s1.async=true;
 s1.src='http://souders.org/tests/selfupdating/boo
   tstrap.js’;
 var
   s0=document.getElementsByTagName('script’)[0];
 s0.parentNode.insertBefore(s1, s0);




stevesouders.com/tests/selfupdating/
send beacon:
 http://souders.org/tests/selfupdating/beacon.js?v
   =02:29:53


 beacon response triggers
  update:
 var iframe1 = document.createElement("iframe");
 iframe1.style.display = "none”;
 iframe1.src =
   "http://souders.org/tests/selfupdating/update.p
   hp?v=02:29:53";
 document.body.appendChild(iframe1);
stevesouders.com/tests/selfupdating/
iframe reloads itself:
 <script
   src="http://souders.org/tests/selfupdating/boot
   strap.js">
 </script>
 <script>
 if (location.hash === '') {
   location.hash = "check”;
   location.reload(true);
 }
 </script>

 reload triggers Conditional GET
 cached script is updated
stevesouders.com/tests/selfupdating/
voilà
bootstrap scripts can have long
 cache times
AND
get updated when necessary
caveats
the update is used on the next
 page view (like app cache)
1 reported IE8 issue
takeaways
load 3rd party scripts async
test your site with
 blackhole.webpagetest.org
have RUM timeout
make bootstrap scripts self-
 updating & increase cache
 times
Steve Souders
                                        @souders
stevesouders.com/docs/fluent-snippets-20120530.pptx

High Performance Snippets

  • 1.
    High Performance Snippets stevesouders.com/docs/fluent-snippets-20120530.pptx Disclaimer: This content does not necessarily reflect the opinions of my employer.
  • 3.
    synchronous scripts block allfollowing elements from rendering in all browsers
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
    /etc/hosts: 72.66.115.13 apis.google.com 72.66.115.13 www.google-analytics.com 72.66.115.13static.ak.fbcdn.net 72.66.115.13 connect.facebook.net 72.66.115.13 platform.twitter.com 72.66.115.13 widgets.twimg.com WebPagetest: setDnsName apis.google.com blackhole.webpagetest.org setDnsName www.google-analytics.com blackhole.webpagetest.org setDnsName static.ak.fbcdn.net blackhole.webpagetest.org setDnsName connect.facebook.net blackhole.webpagetest.org setDnsName platform.twitter.com blackhole.webpagetest.org setDnsName widgets.twimg.com blackhole.webpagetest.org navigate http://www.businessinsider.com/
  • 13.
    original snippet <script src="http://widgets.twimg.com/j/2/widget.js"> </script> <script> newTWTR.Widget({ version: 2, type: 'profile', ... }).render().setUser('souders').start(); </script>
  • 14.
    <script> asyncified snippet function doTwitter() { if ( this.readyState && this.readyState != "complete" && this.readyState != "loaded" ) { return; } this.onload = this.onreadystatechange = null; new TWTR.Widget({ version: 2, type: 'profile', ... }).render().setUser('souders').start(); } var ts = document.createElement("script"); ts.async = true; ts.onload = ts.onreadystatechange = doTwitter; ts.src = "http://widgets.twimg.com/j/2/widget.js"; var s0 = document.getElementsByTagName('script')[0]; s0.parentNode.insertBefore(ts, s0); </script>
  • 15.
    But... you can’tmake a script async if it does document.write widget.js does document.write: init: function(x) { ... this.id = x.id || "twtr-widget-" + this._widgetNumber; if (!x.id) { document.write('<div class="twtr-widget" id="' + this.id + '"></div>') } } What if we create the DIV and specify the id?
  • 16.
    asyncified snippet plusDIV <div class=‘twtr-widget’ id=‘souderstwitter’></div> <script> function doTwitter() { if ( this.readyState && this.readyState != "complete" && this.readyState != "loaded" ) { return; } this.onload = this.onreadystatechange = null; new TWTR.Widget({ id: ‘souderstwitter’, version: 2, type: 'profile', ... }).render().setUser('souders').start(); } var ts = document.createElement("script"); ts.async = true; ...
  • 17.
  • 18.
  • 19.
    While placing JavaScriptfiles at the bottom of the page is a best practice for website performance, when including the anywhere.js file, always place the file as close to the top of the page as possible. The anywhere.js file is small (<3KB) and is delivered to the page GZIP'd. Further, all dependancies for @Anywhere features are loaded asynchronously, on-demand so as to not impact performance of the host page.
  • 20.
    three facts: 1.failures happen 2. 304 & 200 both produce frontend SPOF 3. anywhere.js expires after 15 minutes
  • 21.
    snippet cache times http://platform.twitter.com/widgets.js- 30 mins http://connect.facebook.net/en_US/all.js - 15 mins http://www.google-analytics.com/ga.js - 120 mins
  • 22.
    “bootstrap scripts” oftenhave short cache times more frequent Conditional GET requests means frontend SPOF is more likely but short cache times is the only way snippet owners can push updates or is it?
  • 23.
  • 24.
    part 1: updatenotification piggyback on dynamic request pass cached version # to server: ?v=127 server returns: 204 – no update JS – new version available
  • 25.
    part 2: overwritecache re-request dynamically rev the URL (querystring) XHR w/ setRequestHeader reload iframe containing bootstrap script
  • 26.
    example load bootstrapscript: var s1=document.createElement('script'); s1.async=true; s1.src='http://souders.org/tests/selfupdating/boo tstrap.js’; var s0=document.getElementsByTagName('script’)[0]; s0.parentNode.insertBefore(s1, s0); stevesouders.com/tests/selfupdating/
  • 27.
    send beacon: http://souders.org/tests/selfupdating/beacon.js?v =02:29:53 beacon response triggers update: var iframe1 = document.createElement("iframe"); iframe1.style.display = "none”; iframe1.src = "http://souders.org/tests/selfupdating/update.p hp?v=02:29:53"; document.body.appendChild(iframe1); stevesouders.com/tests/selfupdating/
  • 28.
    iframe reloads itself: <script src="http://souders.org/tests/selfupdating/boot strap.js"> </script> <script> if (location.hash === '') { location.hash = "check”; location.reload(true); } </script> reload triggers Conditional GET cached script is updated stevesouders.com/tests/selfupdating/
  • 29.
    voilà bootstrap scripts canhave long cache times AND get updated when necessary
  • 30.
    caveats the update isused on the next page view (like app cache) 1 reported IE8 issue
  • 31.
    takeaways load 3rd partyscripts async test your site with blackhole.webpagetest.org have RUM timeout make bootstrap scripts self- updating & increase cache times
  • 33.
    Steve Souders @souders stevesouders.com/docs/fluent-snippets-20120530.pptx

Editor's Notes

  • #2 flickr.com/photos/bestrated1/2141687384/
  • #3 WidgetsAdsAnalytics
  • #11 http://www.webpagetest.org/result/120530_HS_4BA/
  • #13 http://www.webpagetest.org/result/120530_7R_4BJ/
  • #18 http://www.webpagetest.org/result/120530_7R_4BJ/
  • #19 http://www.webpagetest.org/result/120530_8D_4BQ/
  • #22 flickr.com/photos/wwarby/3296379139/
  • #23 flickr.com/photos/juditk/5024772809/whether it’s 1 or 5 requests, frontend SPOF will still happen
  • #32 flickr.com/photos/myklroventine/4062102754/