Mitigating Advertisement Impact on Page Performance

35
MITIGATING ADVERTISEMENT IMPACT ON PAGE PERFORMANCE by Ismail Elshareef Friday, October 22, 2010

Transcript of Mitigating Advertisement Impact on Page Performance

Page 1: Mitigating Advertisement Impact on Page Performance

MITIGATING ADVERTISEMENT IMPACT ON PAGE PERFORMANCE by Ismail Elshareef

Friday, October 22, 2010

Page 2: Mitigating Advertisement Impact on Page Performance

ISMAIL ELSHAREEFEdmunds, Inc.

@codeish@EdmundsLabs

Friday, October 22, 2010

Page 3: Mitigating Advertisement Impact on Page Performance

EDMUNDS, INC.

Online since 1995 Properties:150M+ page views/month Revenue = Ads + Leads

Friday, October 22, 2010

Page 4: Mitigating Advertisement Impact on Page Performance

IN 2008 ... A VISION WAS BORN

Friday, October 22, 2010

Page 5: Mitigating Advertisement Impact on Page Performance

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

Page 6: Mitigating Advertisement Impact on Page Performance

OUR DILEMMA

3rd-PARTY CODE PERFORMANCE

UXD

Friday, October 22, 2010

Page 7: Mitigating Advertisement Impact on Page Performance

Fast WITHOUT3 rd Party

Fast WITH 3rd Party Code

Friday, October 22, 2010

Page 8: Mitigating Advertisement Impact on Page Performance

• 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

Page 9: Mitigating Advertisement Impact on Page Performance

MISSION:CONTROL 3RD-PARTY JS

Friday, October 22, 2010

Page 10: Mitigating Advertisement Impact on Page Performance

INITIAL ATTEMPTSapplies to 3rd-Party JavaScript Code ONLY

Override document.write

iFrame’n’Copy

Friday, October 22, 2010

Page 11: Mitigating Advertisement Impact on Page Performance

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

Page 12: Mitigating Advertisement Impact on Page Performance

(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

Page 13: Mitigating Advertisement Impact on Page Performance

JAVASCRIPT LOADER

Friday, October 22, 2010

Page 14: Mitigating Advertisement Impact on Page Performance

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

Page 15: Mitigating Advertisement Impact on Page Performance

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

Page 16: Mitigating Advertisement Impact on Page Performance

HOW DOES THE LOADER WORK?

Friday, October 22, 2010

Page 17: Mitigating Advertisement Impact on Page Performance

addModule

execControl

addControl

timerfilesmodulesqueue

PAGESETUP

HOW DOES THE LOADER WORK?

Friday, October 22, 2010

Page 18: Mitigating Advertisement Impact on Page Performance

<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

Page 19: Mitigating Advertisement Impact on Page Performance

<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

Page 20: Mitigating Advertisement Impact on Page Performance

<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

Page 21: Mitigating Advertisement Impact on Page Performance

<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

Page 22: Mitigating Advertisement Impact on Page Performance

<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

Page 23: Mitigating Advertisement Impact on Page Performance

<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

Page 24: Mitigating Advertisement Impact on Page Performance

<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

Page 25: Mitigating Advertisement Impact on Page Performance

<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

Page 26: Mitigating Advertisement Impact on Page Performance

WHY CREATE OUR OWN LOADER?

Run JS chunks in order of priority

Allow a Debug Mode

Decouple from DOM events

Friday, October 22, 2010

Page 27: Mitigating Advertisement Impact on Page Performance

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

Page 28: Mitigating Advertisement Impact on Page Performance

With Ads

Without Ads

INSIDELINE.COM STATS

Friday, October 22, 2010

Page 29: Mitigating Advertisement Impact on Page Performance

ANOTHER VISION WAS BORN

Friday, October 22, 2010

Page 30: Mitigating Advertisement Impact on Page Performance

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

Page 31: Mitigating Advertisement Impact on Page Performance

PAGESPEED SCORES

0

22.5

45

67.5

90

PageSpeed

Legacy Site Beta Site

8765

Friday, October 22, 2010

Page 32: Mitigating Advertisement Impact on Page Performance

INITIAL RESULTS

17%Total Page Views Per Session

Friday, October 22, 2010

Page 33: Mitigating Advertisement Impact on Page Performance

(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

Page 34: Mitigating Advertisement Impact on Page Performance

WE ARE HIRING!http://www.edmunds.com/help/about/jobs/

Friday, October 22, 2010

Page 35: Mitigating Advertisement Impact on Page Performance

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