mitigating advertisement impact on page performance
Post on 24-Jun-2015
1.298 Views
Preview:
TRANSCRIPT
MITIGATING ADVERTISEMENT IMPACT ON PAGE PERFORMANCE by Ismail Elshareef
Friday, October 22, 2010
ISMAIL ELSHAREEFEdmunds, Inc.
@codeish@EdmundsLabs
Friday, October 22, 2010
EDMUNDS, INC.
Online since 1995 Properties:150M+ page views/month Revenue = Ads + Leads
Friday, October 22, 2010
IN 2008 ... A VISION WAS BORN
Friday, October 22, 2010
REDESIGN OBJECTIVES
PERFORMANCE (Page onLoad in < 1.5 sec)
RICHER CONTENT (Flash, video, slicker UXD, ...etc)
BETTER REVENUE (Only positive impact on ad impressions)
Friday, October 22, 2010
OUR DILEMMA
3rd-PARTY CODE PERFORMANCE
UXD
Friday, October 22, 2010
Fast WITHOUT3 rd Party
Fast WITH 3rd Party Code
Friday, October 22, 2010
• Fixed width/height• Easy to late-load• Sandboxed Code
iFrame JavaScriptOR
• Cannot lazy-load• Access to DOM• Richer Content
FORMS OF 3RD-PARTY CODE
• Disadvantage• Advantage
Friday, October 22, 2010
MISSION:CONTROL 3RD-PARTY JS
Friday, October 22, 2010
INITIAL ATTEMPTSapplies to 3rd-Party JavaScript Code ONLY
Override document.write
iFrame’n’Copy
Friday, October 22, 2010
INITIAL ATTEMPTSapplies to 3rd-Party JavaScript Code ONLY
Override document.write
iFrame’n’Copy
WE LEARNED THAT ...
3rd-Party JS Code should be treated as
Friday, October 22, 2010
(I) CAN’T CONTROL IT ALL
(II) SPEED UP WHAT YOU CAN (Your code and lazy-loadable code)
(III) DEFER THE REST (All code that cannot be lazy-loaded)
OUR NEWFOUND CREED
Friday, October 22, 2010
JAVASCRIPT LOADER
Friday, October 22, 2010
3RD-PARTYHANDLING
LOGIC
A
Is this an ad?
Is this a JS ad?
Is this a JS module?NO
YES
Create placeholder
markup
NO
Request JS file after loader is
includedB
Create iframe placeholder
markup
YES
NO
Add JS chunk to Loader loading the iframe after page
load event
Create placeholder
markup
Request JS file after loader is
includedB
Create iFrame placeholder
markupLazy-load iFrame with JS Loader
YES
DONE
DONE
Friday, October 22, 2010
3RD-PARTYJAVASCRIPTHANDLING
LOGIC
B
JS Components?
DONE
NO
load in a hidden DIV
YES
.html?disableallthird
party=yes
.html?disableallads=
yes
.html?disableadnum
ber=[int]
YES
is ad?
NO
NO
YES
YES
NOis ad
position == [int]?
YES
YES
<script> is done loading
move content to placeholder (collapse
when appropriate)
NO NO
Friday, October 22, 2010
HOW DOES THE LOADER WORK?
Friday, October 22, 2010
addModule
execControl
addControl
timerfilesmodulesqueue
PAGESETUP
HOW DOES THE LOADER WORK?
Friday, October 22, 2010
<script type="text/javascript">
//<![CDATA[
PAGESETUP = {
timer: {start: (new Date).getTime()},
files: [],
modules: {},
queue: {high:[], normal:[], low:[]},
addModule: function(mod) {
if (PAGESETUP.modules[mod]) {
++PAGESETUP.modules[mod];
} else {
PAGESETUP.modules[mod] = 1;
}
},
execControls: function(start) {
if (!this.merged) {
this.merged = PAGESETUP.queue.high;
this.merged = this.merged.concat(PAGESETUP.queue.normal).concat(PAGESETUP.queue.low);
}
var merged = this.merged;
setTimeout(function() {
var item = merged.shift();
if (merged.length > 0) {
setTimeout(arguments.callee, 10);
}
item.call();
}, 0);
},
addControl: function(fn, priority) {
switch(priority) {
case 'high':
this.queue.high.push(fn);
break;
case 'low':
this.queue.low.push(fn);
break;
case 'normal':
default:
this.queue.normal.push(fn);
break;
}
}
};
//]]>
</script>
addModule
execControl
addControl
timerfilesmodulesqueue
PAGESETUP
HOW DOES THE LOADER WORK?
Friday, October 22, 2010
<script type="text/javascript">
//<![CDATA[
PAGESETUP = {
timer: {start: (new Date).getTime()},
files: [],
modules: {},
queue: {high:[], normal:[], low:[]},
addModule: function(mod) {
if (PAGESETUP.modules[mod]) {
++PAGESETUP.modules[mod];
} else {
PAGESETUP.modules[mod] = 1;
}
},
execControls: function(start) {
if (!this.merged) {
this.merged = PAGESETUP.queue.high;
this.merged = this.merged.concat(PAGESETUP.queue.normal).concat(PAGESETUP.queue.low);
}
var merged = this.merged;
setTimeout(function() {
var item = merged.shift();
if (merged.length > 0) {
setTimeout(arguments.callee, 10);
}
item.call();
}, 0);
},
addControl: function(fn, priority) {
switch(priority) {
case 'high':
this.queue.high.push(fn);
break;
case 'low':
this.queue.low.push(fn);
break;
case 'normal':
default:
this.queue.normal.push(fn);
break;
}
}
};
//]]>
</script>
addModule
execControl
addControl
timerfilesmodulesqueue
PAGESETUP
HOW DOES THE LOADER WORK?
Friday, October 22, 2010
<script type="text/javascript">
//<![CDATA[
PAGESETUP = {
timer: {start: (new Date).getTime()},
files: [],
modules: {},
queue: {high:[], normal:[], low:[]},
addModule: function(mod) {
if (PAGESETUP.modules[mod]) {
++PAGESETUP.modules[mod];
} else {
PAGESETUP.modules[mod] = 1;
}
},
execControls: function(start) {
if (!this.merged) {
this.merged = PAGESETUP.queue.high;
this.merged = this.merged.concat(PAGESETUP.queue.normal).concat(PAGESETUP.queue.low);
}
var merged = this.merged;
setTimeout(function() {
var item = merged.shift();
if (merged.length > 0) {
setTimeout(arguments.callee, 10);
}
item.call();
}, 0);
},
addControl: function(fn, priority) {
switch(priority) {
case 'high':
this.queue.high.push(fn);
break;
case 'low':
this.queue.low.push(fn);
break;
case 'normal':
default:
this.queue.normal.push(fn);
break;
}
}
};
//]]>
</script>
addModule
execControl
addControl
timerfilesmodulesqueue
PAGESETUP
HOW DOES THE LOADER WORK?
Friday, October 22, 2010
<script type="text/javascript">
//<![CDATA[
PAGESETUP = {
timer: {start: (new Date).getTime()},
files: [],
modules: {},
queue: {high:[], normal:[], low:[]},
addModule: function(mod) {
if (PAGESETUP.modules[mod]) {
++PAGESETUP.modules[mod];
} else {
PAGESETUP.modules[mod] = 1;
}
},
execControls: function(start) {
if (!this.merged) {
this.merged = PAGESETUP.queue.high;
this.merged = this.merged.concat(PAGESETUP.queue.normal).concat(PAGESETUP.queue.low);
}
var merged = this.merged;
setTimeout(function() {
var item = merged.shift();
if (merged.length > 0) {
setTimeout(arguments.callee, 10);
}
item.call();
}, 0);
},
addControl: function(fn, priority) {
switch(priority) {
case 'high':
this.queue.high.push(fn);
break;
case 'low':
this.queue.low.push(fn);
break;
case 'normal':
default:
this.queue.normal.push(fn);
break;
}
}
};
//]]>
</script>
addModule
execControl
addControl
timerfilesmodulesqueue
PAGESETUP
!"#$%&'(')&*+,'*-'./010"#$%&',("$#+,&0'2.'3.0&%.4305*$.4305*$6/",7!."#$%&'7
HOW DOES THE LOADER WORK?
Friday, October 22, 2010
<script type="text/javascript">
//<![CDATA[
PAGESETUP = {
timer: {start: (new Date).getTime()},
files: [],
modules: {},
queue: {high:[], normal:[], low:[]},
addModule: function(mod) {
if (PAGESETUP.modules[mod]) {
++PAGESETUP.modules[mod];
} else {
PAGESETUP.modules[mod] = 1;
}
},
execControls: function(start) {
if (!this.merged) {
this.merged = PAGESETUP.queue.high;
this.merged = this.merged.concat(PAGESETUP.queue.normal).concat(PAGESETUP.queue.low);
}
var merged = this.merged;
setTimeout(function() {
var item = merged.shift();
if (merged.length > 0) {
setTimeout(arguments.callee, 10);
}
item.call();
}, 0);
},
addControl: function(fn, priority) {
switch(priority) {
case 'high':
this.queue.high.push(fn);
break;
case 'low':
this.queue.low.push(fn);
break;
case 'normal':
default:
this.queue.normal.push(fn);
break;
}
}
};
//]]>
</script>
addModule
execControl
addControl
timerfilesmodulesqueue
PAGESETUP
!"#$%&'(')&*+,'*-'./010"#$%&',("$#+,&0'2.'3.0&%.4305*$.4305*$6/",7!."#$%&'7
HOW DOES THE LOADER WORK?
- Loads global core libs (with YUI libs)
Friday, October 22, 2010
<script type="text/javascript">
//<![CDATA[
PAGESETUP = {
timer: {start: (new Date).getTime()},
files: [],
modules: {},
queue: {high:[], normal:[], low:[]},
addModule: function(mod) {
if (PAGESETUP.modules[mod]) {
++PAGESETUP.modules[mod];
} else {
PAGESETUP.modules[mod] = 1;
}
},
execControls: function(start) {
if (!this.merged) {
this.merged = PAGESETUP.queue.high;
this.merged = this.merged.concat(PAGESETUP.queue.normal).concat(PAGESETUP.queue.low);
}
var merged = this.merged;
setTimeout(function() {
var item = merged.shift();
if (merged.length > 0) {
setTimeout(arguments.callee, 10);
}
item.call();
}, 0);
},
addControl: function(fn, priority) {
switch(priority) {
case 'high':
this.queue.high.push(fn);
break;
case 'low':
this.queue.low.push(fn);
break;
case 'normal':
default:
this.queue.normal.push(fn);
break;
}
}
};
//]]>
</script>
addModule
execControl
addControl
timerfilesmodulesqueue
PAGESETUP
!"#$%&'(')&*+,'*-'./010"#$%&',("$#+,&0'2.'3.0&%.4305*$.4305*$6/",7!."#$%&'7
HOW DOES THE LOADER WORK?
- Loads global core libs (with YUI libs)- Executes JS chunks in priority in 25 ms intv.
Friday, October 22, 2010
<script type="text/javascript">
//<![CDATA[
PAGESETUP = {
timer: {start: (new Date).getTime()},
files: [],
modules: {},
queue: {high:[], normal:[], low:[]},
addModule: function(mod) {
if (PAGESETUP.modules[mod]) {
++PAGESETUP.modules[mod];
} else {
PAGESETUP.modules[mod] = 1;
}
},
execControls: function(start) {
if (!this.merged) {
this.merged = PAGESETUP.queue.high;
this.merged = this.merged.concat(PAGESETUP.queue.normal).concat(PAGESETUP.queue.low);
}
var merged = this.merged;
setTimeout(function() {
var item = merged.shift();
if (merged.length > 0) {
setTimeout(arguments.callee, 10);
}
item.call();
}, 0);
},
addControl: function(fn, priority) {
switch(priority) {
case 'high':
this.queue.high.push(fn);
break;
case 'low':
this.queue.low.push(fn);
break;
case 'normal':
default:
this.queue.normal.push(fn);
break;
}
}
};
//]]>
</script>
addModule
execControl
addControl
timerfilesmodulesqueue
PAGESETUP
!"#$%&'(')&*+,'*-'./010"#$%&',("$#+,&0'2.'3.0&%.4305*$.4305*$6/",7!."#$%&'7
HOW DOES THE LOADER WORK?
- Loads global core libs (with YUI libs)- Executes JS chunks in priority in 25 ms intv.- Has debugging features ?jsflag=full
Friday, October 22, 2010
<script type="text/javascript">
//<![CDATA[
PAGESETUP = {
timer: {start: (new Date).getTime()},
files: [],
modules: {},
queue: {high:[], normal:[], low:[]},
addModule: function(mod) {
if (PAGESETUP.modules[mod]) {
++PAGESETUP.modules[mod];
} else {
PAGESETUP.modules[mod] = 1;
}
},
execControls: function(start) {
if (!this.merged) {
this.merged = PAGESETUP.queue.high;
this.merged = this.merged.concat(PAGESETUP.queue.normal).concat(PAGESETUP.queue.low);
}
var merged = this.merged;
setTimeout(function() {
var item = merged.shift();
if (merged.length > 0) {
setTimeout(arguments.callee, 10);
}
item.call();
}, 0);
},
addControl: function(fn, priority) {
switch(priority) {
case 'high':
this.queue.high.push(fn);
break;
case 'low':
this.queue.low.push(fn);
break;
case 'normal':
default:
this.queue.normal.push(fn);
break;
}
}
};
//]]>
</script>
addModule
execControl
addControl
timerfilesmodulesqueue
PAGESETUP
!"#$%&'(')&*+,'*-'./010"#$%&',("$#+,&0'2.'3.0&%.4305*$.4305*$6/",7!."#$%&'7
HOW DOES THE LOADER WORK?
- Loads global core libs (with YUI libs)- Executes JS chunks in priority in 25 ms intv.- Has debugging features ?jsflag=full- Ability to exclude 3rd party code
Friday, October 22, 2010
WHY CREATE OUR OWN LOADER?
Run JS chunks in order of priority
Allow a Debug Mode
Decouple from DOM events
Friday, October 22, 2010
3RD-PARTY CODE WITH JS LOADER
Lazy-load in desired priority
iFrames JavaScriptOR
Include after Loader include
<iframe id=”ad1” width=”300” height=”250”>// add JS chunk to loader.........<script src=”loader.js”></script>// execute JS chunk through loader</body>
<div id=”ad2”></div>...............<script src=”loader.js”></script>// Handle JavaScript ads</body>
Friday, October 22, 2010
With Ads
Without Ads
INSIDELINE.COM STATS
Friday, October 22, 2010
ANOTHER VISION WAS BORN
Friday, October 22, 2010
HTTP REQUESTS
0
50
100
150
200
Homepage New Cars Used Cars
Legacy Site Beta Site
152 135 111
44 72 44
Friday, October 22, 2010
PAGESPEED SCORES
0
22.5
45
67.5
90
PageSpeed
Legacy Site Beta Site
8765
Friday, October 22, 2010
INITIAL RESULTS
17%Total Page Views Per Session
Friday, October 22, 2010
(I) CAN’T CONTROL IT ALL
(II) SPEED UP WHAT YOU CAN (Your code and lazy-loadable code)
(III) DEFER THE REST (All code that cannot be lazy-loaded)
AGAIN ... OUR NEWFOUND CREED
Friday, October 22, 2010
WE ARE HIRING!http://www.edmunds.com/help/about/jobs/
Friday, October 22, 2010
THANK YOU!ISMAIL ELSHAREEFEdmunds, Inc.
WE ARE HIRING!http://www.edmunds.com/help/about/jobs/
@codeish@EdmundsLabs
Photo Credits:http://farm3.static.flickr.com/2203/2498445479_064841a97d_o.jpghttp://jcreviews.files.wordpress.com/2010/03/battlestar-galactica.jpghttp://img.wallpaperstock.net:81/crossroads-in-life-wallpapers_10124_1600x1200.jpghttp://upload.wikimedia.org/wikipedia/commons/0/01/Stapler-swingline-red.jpg
Friday, October 22, 2010
top related