Improving 3rd Party Script Performance with
<IFRAME>s
Philip Tellis / philip@bluesmoon.info
Velocity 2013 / 2013-06-20
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 1
• Philip Tellis
• @bluesmoon
• philip@bluesmoon.info
• SOASTA
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 2
Do you use JavaScript?
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 3
<script src="..."></script>
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 4
<script src>
• Works well with browser lookahead
• But blocks everything
• Yes, you can use async or defer
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 5
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 6
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 7
document.createElement("script");
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 8
dynamic script node
1 Loads in parallel with the rest of the page
2 Still blocks the onload event
3 No telling when it will load up
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 9
The Method Queue Pattern
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 10
MQP
var _mq = _mq || [];
var s = document.createElement("script"),
t = document.getElementsByTagName("script")[0];
s.src="http://some.site.com/script.js";
t.parentNode.insertBefore(s, t);
// script.js will be available some time in the
// future, but we can call its methods
_mq.push(["method1", list, of, params]);
_mq.push(["method2", other, params]);
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 11
MQP
var self = this;
_mq = _mq || [];
while(_mq.length) {
// remove the first item from the queue
var params = _mq.shift();
// remove the method from the first item
var method = params.shift();
self[method].apply(self, params);
}
_mq.push = function(params) {
// remove the method from the first item
var method = params.shift();
self[method].apply(self, params);
}
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 12
That takes care of #3
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 13
But we still block onload
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 14
IFRAMEs to the rescue
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 15
But IFRAMEs block onload until the subpage has
loaded
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 16
(This sub-page intentionally left blank)
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 17
So here’s the code – Section I
// Section 1 - Create the iframe
var dom,doc,where,
iframe = document.createElement("iframe");
iframe.src = "javascript:false";
(iframe.frameElement || iframe).style.cssText =
"width: 0; height: 0; border: 0";
where = document.getElementsByTagName("script");
where = where[where.length - 1];
where.parentNode.insertBefore(iframe, where);
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 18
javascript:false is key to solving most
cross-domain issues
Ask me about about:blank
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 19
Except if the page developer sets
document.domain
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 20
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 21
The code – Section II
// Section 2 - handle document.domain
try {
doc = iframe.contentWindow.document;
}
catch(e) {
dom = document.domain;
iframe.src =
"javascript:var d=document.open();" +
"d.domain=’" + dom + "’;" +
"void(0);";
doc = iframe.contentWindow.document;
}
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 22
Only set document.domain if it has already
been set!
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 23
The code – Section III
// Section 3 - tell the iframe to load our script
doc.open()._l = function() {
var js = this.createElement("script");
if(dom)
this.domain = dom;
js.id = "js-iframe-async";
js.src = script_url;
this.body.appendChild(js);
};
doc.write(’<body onload="document._l();">’);
doc.close();
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 24
Notice that we’ve set document.domain again
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 25
Inside this function, document is the parent
document and this is the iframe!
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 26
Also, global variables inside _l() are global to the
parent window
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 27
Modify the MQP for IFRAME support
GLOBAL = window;
// Running in an iframe, and our script node’s
// id is js-iframe-async
if(window.parent != window &&
document.getElementById("js-iframe-async")) {
GLOBAL = window.parent;
}
GLOBAL._mq = GLOBAL._mq || [];
_mq = GLOBAL._mq;
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 28
GLOBAL refers to the parent window and window
refers to the iframe
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 29
So attach events to GLOBAL
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 30
Summary
• Create an iframe with src set to javascript:false
• Set document.domain if needed (twice)
• Write dynamic script node into iframe on iframe’s onload
event
• Alias parent window into iframe
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 31
Result: Happy Customers
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 32
Read all about it
• http://lognormal.com/blog/2012/12/12/the-script-loader-
pattern/
• https://www.w3.org/Bugs/Public/show_bug.cgi?id=21074
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 33
Cache busting with a far-future expires header
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 34
Some more code...
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 35
location.reload(true);
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 36
More completely
<script src="SCRIPT.js"></script>
<script>
var reqd_ver = location.search;
window.onload = function() {
var ver = SCRIPT.version;
if (ver < reqd_ver) {
location.reload(true);
}
};
</script>
The condition protects us from an infinite loop with bad proxies
and Firefox 3.5.11
Note: Don’t use location.hash – it messes with history on IE8.
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 37
And the blog post...
http://www.lognormal.com/blog/2012/06/17/more-
on-updating-boomerang/
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 38
Join us right after this guy...
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 39
Revolutionary RUM
1 Combine 1oz Cane Rum, 3/4oz Blood Orange Puree, &
1/2oz citrus infused syrup in a mixing glass
2 Add ice and shake vigourously
3 Strain into a chilled cocktail glass
4 Top with lime-mint foam
17:45, Evolution Café + Bar, Hyatt Lobby
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 40
• Philip Tellis
• @bluesmoon
• philip@bluesmoon.info
• www.SOASTA.com
• boomerang
• LogNormal Blog
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 41
Image Credits
• Stop Hammertime by Rich Anderson
http://www.flickr.com/photos/memestate/54408373/
• Nicholas Zakas by Ben Alman
http://www.flickr.com/photos/rj3/5635837522/
Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 42

Improving 3rd Party Script Performance With IFrames

  • 1.
    Improving 3rd PartyScript Performance with <IFRAME>s Philip Tellis / philip@bluesmoon.info Velocity 2013 / 2013-06-20 Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 1
  • 2.
    • Philip Tellis •@bluesmoon • philip@bluesmoon.info • SOASTA Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 2
  • 3.
    Do you useJavaScript? Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 3
  • 4.
    <script src="..."></script> Velocity 2013/ 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 4
  • 5.
    <script src> • Workswell with browser lookahead • But blocks everything • Yes, you can use async or defer Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 5
  • 6.
    Velocity 2013 /2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 6
  • 7.
    Velocity 2013 /2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 7
  • 8.
    document.createElement("script"); Velocity 2013 /2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 8
  • 9.
    dynamic script node 1Loads in parallel with the rest of the page 2 Still blocks the onload event 3 No telling when it will load up Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 9
  • 10.
    The Method QueuePattern Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 10
  • 11.
    MQP var _mq =_mq || []; var s = document.createElement("script"), t = document.getElementsByTagName("script")[0]; s.src="http://some.site.com/script.js"; t.parentNode.insertBefore(s, t); // script.js will be available some time in the // future, but we can call its methods _mq.push(["method1", list, of, params]); _mq.push(["method2", other, params]); Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 11
  • 12.
    MQP var self =this; _mq = _mq || []; while(_mq.length) { // remove the first item from the queue var params = _mq.shift(); // remove the method from the first item var method = params.shift(); self[method].apply(self, params); } _mq.push = function(params) { // remove the method from the first item var method = params.shift(); self[method].apply(self, params); } Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 12
  • 13.
    That takes careof #3 Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 13
  • 14.
    But we stillblock onload Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 14
  • 15.
    IFRAMEs to therescue Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 15
  • 16.
    But IFRAMEs blockonload until the subpage has loaded Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 16
  • 17.
    (This sub-page intentionallyleft blank) Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 17
  • 18.
    So here’s thecode – Section I // Section 1 - Create the iframe var dom,doc,where, iframe = document.createElement("iframe"); iframe.src = "javascript:false"; (iframe.frameElement || iframe).style.cssText = "width: 0; height: 0; border: 0"; where = document.getElementsByTagName("script"); where = where[where.length - 1]; where.parentNode.insertBefore(iframe, where); Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 18
  • 19.
    javascript:false is keyto solving most cross-domain issues Ask me about about:blank Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 19
  • 20.
    Except if thepage developer sets document.domain Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 20
  • 21.
    Velocity 2013 /2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 21
  • 22.
    The code –Section II // Section 2 - handle document.domain try { doc = iframe.contentWindow.document; } catch(e) { dom = document.domain; iframe.src = "javascript:var d=document.open();" + "d.domain=’" + dom + "’;" + "void(0);"; doc = iframe.contentWindow.document; } Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 22
  • 23.
    Only set document.domainif it has already been set! Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 23
  • 24.
    The code –Section III // Section 3 - tell the iframe to load our script doc.open()._l = function() { var js = this.createElement("script"); if(dom) this.domain = dom; js.id = "js-iframe-async"; js.src = script_url; this.body.appendChild(js); }; doc.write(’<body onload="document._l();">’); doc.close(); Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 24
  • 25.
    Notice that we’veset document.domain again Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 25
  • 26.
    Inside this function,document is the parent document and this is the iframe! Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 26
  • 27.
    Also, global variablesinside _l() are global to the parent window Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 27
  • 28.
    Modify the MQPfor IFRAME support GLOBAL = window; // Running in an iframe, and our script node’s // id is js-iframe-async if(window.parent != window && document.getElementById("js-iframe-async")) { GLOBAL = window.parent; } GLOBAL._mq = GLOBAL._mq || []; _mq = GLOBAL._mq; Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 28
  • 29.
    GLOBAL refers tothe parent window and window refers to the iframe Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 29
  • 30.
    So attach eventsto GLOBAL Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 30
  • 31.
    Summary • Create aniframe with src set to javascript:false • Set document.domain if needed (twice) • Write dynamic script node into iframe on iframe’s onload event • Alias parent window into iframe Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 31
  • 32.
    Result: Happy Customers Velocity2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 32
  • 33.
    Read all aboutit • http://lognormal.com/blog/2012/12/12/the-script-loader- pattern/ • https://www.w3.org/Bugs/Public/show_bug.cgi?id=21074 Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 33
  • 34.
    Cache busting witha far-future expires header Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 34
  • 35.
    Some more code... Velocity2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 35
  • 36.
    location.reload(true); Velocity 2013 /2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 36
  • 37.
    More completely <script src="SCRIPT.js"></script> <script> varreqd_ver = location.search; window.onload = function() { var ver = SCRIPT.version; if (ver < reqd_ver) { location.reload(true); } }; </script> The condition protects us from an infinite loop with bad proxies and Firefox 3.5.11 Note: Don’t use location.hash – it messes with history on IE8. Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 37
  • 38.
    And the blogpost... http://www.lognormal.com/blog/2012/06/17/more- on-updating-boomerang/ Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 38
  • 39.
    Join us rightafter this guy... Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 39
  • 40.
    Revolutionary RUM 1 Combine1oz Cane Rum, 3/4oz Blood Orange Puree, & 1/2oz citrus infused syrup in a mixing glass 2 Add ice and shake vigourously 3 Strain into a chilled cocktail glass 4 Top with lime-mint foam 17:45, Evolution Café + Bar, Hyatt Lobby Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 40
  • 41.
    • Philip Tellis •@bluesmoon • philip@bluesmoon.info • www.SOASTA.com • boomerang • LogNormal Blog Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 41
  • 42.
    Image Credits • StopHammertime by Rich Anderson http://www.flickr.com/photos/memestate/54408373/ • Nicholas Zakas by Ben Alman http://www.flickr.com/photos/rj3/5635837522/ Velocity 2013 / 2013-06-20 Improving 3rd Party Script Performance with <IFRAME>s 42