Rethinking online advertising by respecting the user: The load time chapter

来源:互联网 时间:1970-01-01

This is the first installment in a series of posts detailing the steps we are taking to make Imprint a pleasant and non-intrusive online advertising experience

One of my biggest gripes with existing advertising solutions today is how much they’re responsible for the load time of a simple web page. It is not unheard of for a page to take 2x, 3x, 10x longer to load because the publisher ads a new advertising network in hopes of some incremental revenue. Advertising code usually creates three problems.

Loads a lot of heavy Javascript, images, videos, increasing the total size of the page by several MB Coded incorrectly and blocks initial rendering of the page or causes reflows Javascript errors on the page, usually due to conflicts with pre-existing code on the publisher page

Here at Sidelines, when we were designing our flagship advertising product, Imprint, we wanted to account for all three of the above:

Imprint must load all larges images, creatives or videos asynchronously via an XHR call. Same with additional JS libs that may be required. Imprint must load itself inside an iFrame without blocking document.readyor window.onload. Imprint must sandboxe itself inside an invisible iFrame that cannot directly reference the global windowvariable.

Let’s look at #2 & #3 first. We explored a ton of solutions, including the new HTML5 async tag and looked at how others were doing it. In the end, we found that the best technique is one initially coined by the good folks at Meebo and put into a library by the Olark team. Here is what our Javascript advertiser tag looks like:

Imprint example tag

JavaScript

<!-- begin sidelines code --><div id="imprint-div"></div><script data-cfasync="false" type='text/javascript'>/*<![CDATA[*/window.lightningjs||function(c){function g(b,d){d&&(d+=(//?/.test(d)?"&":"?")+"lv=1");c[b]||function(){var i=window,h=document,j=b,g=h.location.protocol,l="load",k=0;(function(){function b(){a.P(l);a.w=1;c[j]("_load")}c[j]=function(){function m(){m.id=e;return c[j].apply(m,arguments)}var b,e=++k;b=this&&this!=i?this.id||0:0;(a.s=a.s||[]).push([e,b,arguments]);m.then=function(b,c,h){var d=a.fh[e]=a.fh[e]||[],j=a.eh[e]=a.eh[e]||[],f=a.ph[e]=a.ph[e]||[];b&&d.push(b);c&&j.push(c);h&&f.push(h);return m};return m};var a=c[j]._={};a.fh={};a.eh={};a.ph={};a.l=d?d.replace(/^/////,(g=="https:"?g:"http:")+"//"):d;a.p={0:+new Date};a.P=function(b){a.p[b]=new Date-a.p[0]};a.w&&b();i.addEventListener?i.addEventListener(l,b,!1):i.attachEvent("on"+l,b);var q=function(){function b(){return["<head></head><",c,' onload="var d=',n,";d.getElementsByTagName('head')[0].",d,"(d.",g,"('script')).",i,"='",a.l,"'/"></",c,">"].join("")}var c="body",e=h[c];if(!e)return setTimeout(q,100);a.P(1);var d="appendChild",g="createElement",i="src",k=h[g]("div"),l=k[d](h[g]("div")),f=h[g]("iframe"),n="document",p;k.style.display="none";e.insertBefore(k,e.firstChild).id=o+"-"+j;f.frameBorder="0";f.id=o+"-frame-"+j;/MSIE[ ]+6/.test(navigator.userAgent)&&(f[i]="javascript:false");f.allowTransparency="true";l[d](f);try{f.contentWindow[n].open()}catch(s){a.domain=h.domain,p="javascript:var d="+n+".open();d.domain='"+h.domain+"';",f[i]=p+"void(0);"}try{var r=f.contentWindow[n];r.write(b());r.close()}catch(t){f[i]=p+'d.write("'+b().replace(/"/g,String.fromCharCode(92)+'"')+'");d.close();'}a.P(2)};a.l&&q()})()}();c[b].lv="1";return c[b]}var o="lightningjs",k=window[o]=g(o);k.require=g;k.modules=c}({});var sidelineslib=lightningjs.require("sidelineslib","//sidelinesapp.com/static/js/sidelines-sdk.min.js")sidelineslib("identify","<UNIQUE_PUBLISHER_CODE_HERE>"),sidelineslib("enableAnalytics"),sidelineslib("display",{remote:"sidelinesapp.com",targetContainerId:"imprint-div"}).then(function(e) { }, function(e) { log(e); });/*]]>*/</script><!-- end sidelines code --> <!--beginsidelinescode--><divid="imprint-div"></div><script data-cfasync="false"type='text/javascript'>/*<![CDATA[*/window.lightningjs||function(c){functiong(b,d){d&&(d+=(//?/.test(d)?"&":"?")+"lv=1");c[b]||function(){vari=window,h=document,j=b,g=h.location.protocol,l="load",k=0;(function(){functionb(){a.P(l);a.w=1;c[j]("_load")}c[j]=function(){functionm(){m.id=e;returnc[j].apply(m,arguments)}varb,e=++k;b=this&&this!=i?this.id||0:0;(a.s=a.s||[]).push([e,b,arguments]);m.then=function(b,c,h){vard=a.fh[e]=a.fh[e]||[],j=a.eh[e]=a.eh[e]||[],f=a.ph[e]=a.ph[e]||[];b&&d.push(b);c&&j.push(c);h&&f.push(h);returnm};returnm};vara=c[j]._={};a.fh={};a.eh={};a.ph={};a.l=d?d.replace(/^/////,(g=="https:"?g:"http:")+"//"):d;a.p={0:+new Date};a.P=function(b){a.p[b]=new Date-a.p[0]};a.w&&b();i.addEventListener?i.addEventListener(l,b,!1):i.attachEvent("on"+l,b);var q=function(){function b(){return["<head></head><",c,' onload="var d=',n,";d.getElementsByTagName('head')[0].",d,"(d.",g,"('script')).",i,"='",a.l,"'/"></",c,">"].join("")}var c="body",e=h[c];if(!e)return setTimeout(q,100);a.P(1);var d="appendChild",g="createElement",i="src",k=h[g]("div"),l=k[d](h[g]("div")),f=h[g]("iframe"),n="document",p;k.style.display="none";e.insertBefore(k,e.firstChild).id=o+"-"+j;f.frameBorder="0";f.id=o+"-frame-"+j;/MSIE[]+6/.test(navigator.userAgent)&&(f[i]="javascript:false");f.allowTransparency="true";l[d](f);try{f.contentWindow[n].open()}catch(s){a.domain=h.domain,p="javascript:var d="+n+".open();d.domain='"+h.domain+"';",f[i]=p+"void(0);"}try{varr=f.contentWindow[n];r.write(b());r.close()}catch(t){f[i]=p+'d.write("'+b().replace(/"/g,String.fromCharCode(92)+'"')+'");d.close();'}a.P(2)};a.l&&q()})()}();c[b].lv="1";returnc[b]}varo="lightningjs",k=window[o]=g(o);k.require=g;k.modules=c}({});varsidelineslib=lightningjs.require("sidelineslib","//sidelinesapp.com/static/js/sidelines-sdk.min.js")sidelineslib("identify","<UNIQUE_PUBLISHER_CODE_HERE>"),sidelineslib("enableAnalytics"),sidelineslib("display",{remote:"sidelinesapp.com",targetContainerId:"imprint-div"}).then(function(e){ },function(e){log(e);});/*]]>*/</script><!--endsidelinescode-->

Quite gnarly, right? We obviously have an unminified version of this for those who want to understand what is going on a bit better. Let’s break down what this does.

Load initial script

The first thing we do is load the script responsible for bootstraping Imprint. This is standard procedure for any 3rd party code added to websites, including things like Google Analytics, Facebook embeds, etc.To load the script without blocking anyone, the lines of gibberish above create a hidden iframe

<div style="display:none"> <iframe frameborder="0" id="imprint-iframe"> <html> <head></head> <body onload="var d=document;d.getElementsByTagName('head')[0].appendChild(d.createElement('script')).src='http://sidelinesapp.com/static/js/sidelines-sdk.min.js'"> </body> </html> </iframe></div> <div style="display:none"> <iframeframeborder="0"id="imprint-iframe"> <html> <head></head> <bodyonload="var d=document;d.getElementsByTagName('head')[0].appendChild(d.createElement('script')).src='http://sidelinesapp.com/static/js/sidelines-sdk.min.js'"> </body> </html> </iframe></div>

Script Size WarningBecause you rarely want to have a long expiration time on the initial script, it is important that it is as small as possible.

Line 5 is what loads our loader script. By creating an empty iframe and delegating loading of our script to its body’s onloadevent, we ensure that the main page rendering does not block. As an added benefit, we are sandboxed here with our own windowglobal. To access the main page DOM, we need to explicitly use window.parent, ensuring we do not accidentally override something.

Load Imprint

After the initial script has been loaded, it is time to load Imprint onto the page. The script we loaded in the previous step will do that by creating another iframe, this one pointing at the Imprint domain. This iframe does not have access to the main page DOM.

Load additional creatives

After Imprint has been loaded, it issues an XHR request for any creatives. The server decides the type of creatives that are appropriate and sends back metadata as JSON. Imprint deserializes the response and instantiates a component for each creative. Each component is responsible for loading any additional images, videos, javascript as needed.



相关阅读:
Top