广告前端代码优化

40
广广广广广广广广 广广广广广 广广广广 广广广广广广广广广广 、、 广广 广广广广广 广广 2010 广 7 广 30 广

Upload: taobaocom

Post on 06-May-2015

3.396 views

Category:

Documents


0 download

DESCRIPTION

淘宝广告技术部李牧同学, 在懒懒分享了《广告前端代码优化》,分享内容充实、实战经验宝贵,其多维度的解决方案更是令人大开眼界。

TRANSCRIPT

Page 1: 广告前端代码优化

广告前端代码优化开发无阻滞、无侵扰、无延迟的广告前端代码

淘宝 广告技术部 李牧2010 年 7 月 30 日

Page 2: 广告前端代码优化

2

1 第三方内容对网站速度的影响

Page 3: 广告前端代码优化

3

第三方内容对网站速度的影响

Velocity 2010:Google -- Don’t Let Third Parties Slow You Down

• 网络是缓慢的 : 平均加载时间 :4.9s• 页面是复杂的 :44 个请求来自 7 个域名 ,平均大小 320KB• 很多加载的内容来自第三方

Page 4: 广告前端代码优化

4

第三方内容对网站速度的影响

Google Adsence top 100 publishers 12.8

Google Analytics top 100 publishers <5

Google Doubleclick top 100 publishers 11.5

Third-party Publisher site % Impact

Digg services.newsweek.com 14

Digg realtalkny.uproxx.com   9

FriendConnect www.artinstructionblog.com 10

FriendConnect friendconnectdirectory.com/Food 30

FacebookConnect truveo.com 17

FacebookConnect www.huffingtonpost.com 12

TribalFusion www.xe.com 53

TribalFusion www.wareseeker.com 31

第三方内容对页面加载时间的影响 :

Page 5: 广告前端代码优化

5

P3PC: 第三方内容性能分析Performance of 3rd Party Content (P3PC) Project by Steve Souders • 广告 (ads), 小部件 (widgets) 和 站点分析工具 (analytics) 是导致网站变慢的一个主要原因 .• P3PC 项目专注于第三方内容的性能分析 .• 目标是找到让第三方内容更快的关键点 , 促进第三方的改进性能 .

Page 6: 广告前端代码优化

6

P3PC: 第三方内容性能分析下表是 P3PC 给出的第三方内容主要性能指标 , 从中我们可以清晰看到 P3PC 主要关注哪些方面 .

Page 7: 广告前端代码优化

7

2 广告埋点分析 , 优化思路和限制

Page 8: 广告前端代码优化

8

广告埋点是怎样结构 ? 如何运行 ?<script> alimama_pid="mm_12852562_1778064_8320227"; alimama_sizecode="910"; alimama_width=270; alimama_height=390; alimama_type="i"; </script> <script src="http://a.alimama.cn/inf.js"></script>

<iframe(script) src="http://t.alimama.com/alimama.php?i=mm_1_1_1&t=2&h=760&w=90&cf=10.1&ctz=8&cg=6bd079cde47&u=a.com%2Fa.html "></iframe(script)>

1. 广告位信息2. 客户端信息3. PV Session 信息4. 所属网页信息

1 2

3 4

inf.js

document.write:

5.Http 请求附加信息 :IP,Cookie,UA( 浏览器标识 ),Refer 等

Page 9: 广告前端代码优化

9

选择这种埋点技术带来的好处业务要点 : 位置明确 + 接口简单 + 速度 + 安全 + 客户端信息 方便安排广告展现位置 : 广告出现在埋点所在处 .

接口代码简单 , 而且发布代码可以嵌入 HTML, 也要能被嵌入到 JS 通过 document.write 输出 .

保障广告展现速度 : 页面解析到埋点处立即触发广告展现保障按效果计费类广告安全 : 展现在广告域的 iframe 中收集足够的客户端信息 :inf.js 保证了动态展现请求中包含足

够的信息 . 竞价类广告的广告请求中必须包含这些信息 .

所依赖的技术实现要点 :

静态 <script> 节点 + document.write("<iframe>")

Page 10: 广告前端代码优化

10

埋点带来的性能问题inf.js 阻滞页面加载inf.js 文件较大 ,Gzip 后 11k,Gzip 前 38k.

一个页面多条广告时 ,JS 重复加载和执行doc.write 引入的 Iframe 节点性能不佳doc.write 引入动态 script 节点依然阻滞页面inf.js 文件缓存时间较短 (2 小时 )

代码发布在客户的网页上 , 无法实现永不过期策略 .代码出现位置未知 , 容易出现无法预知的问题 , 所

以缓存时间仅 2 小时 .

Page 11: 广告前端代码优化

11埋点引入 SPOF( 单一故障点 )带给合作网站稳定方面的侵扰

SPOF: A single point of failure (SPOF) is a part of a system which, if it fails, will stop the entire system from working. ( 一个会被反复提及的概念 )

阻滞不仅仅是速度问题还涉及客户网站的稳定 !

客户网站稳定依赖 CDN 上 inf.js 的稳定还可能依赖 doc.write("<script>") 指向的动态广告服

务的稳定而当严重阻滞发生时 , 问题主要出现在 HTTP 建立连接 ,

等待响应等阶段 . 往往和文件大小关系不大了 .

SLO-JS and how to speed up widgets

Page 12: 广告前端代码优化

12第三方埋点代码优化思路 以及我们在优化时无法绕开的限制

思路一 : 推倒 ! 让用户修改发布代码 ! 寻找不依赖静态<script> 节点和 doc.write 的解决方案 .(案例 : dojox.analytics.Urchin对GA的封装,GA自身的改变)

思路二 : Fast By Default!尽最大可能提升每天数十亿已经加入了广告埋点网页的速度 .(案例 :Google Adsence在Velocity2010最近披露的优化方案)

待解决问题和业务限制 :

脚本阻滞 x2 + 文件大 + 缓存短 + 重复加载 需要解决 !

位置明确 + 接口简单 + 速度 + 安全 + 客户端信息 不能牺牲 !

Page 13: 广告前端代码优化

13

3 无阻脚本下载方案

Page 14: 广告前端代码优化

14

无阻脚本下载方案Steve: Loading Scripts Without Blocking

脚本存在于不同域名下无阻加载备选方案 :Script DeferScript DOM ElementDoc.write Script in Iframe

Doc.write Script in Iframe

Page 15: 广告前端代码优化

15Defer 载入脚本 或 DomReady 时展现广告 . 速度不符合要求

网站 频道domready(s)↑ onload(s)

domready/onload(%)

163 mail 0.257 15.6 1.65%qq qzone 0.525 0.83 63.25%baidu tieba 0.599 0.753 79.55%qq news 1.354 4.94 27.41%youku video 1.54 1.86 82.80%sohu news 3.185 3.7 86.08%google mail 3.95 13.32 29.65%sohu blog 3.992 4.34 91.98%sina sports 5.11 7.2 70.97%sina blog 5.457 9.12 59.84%taobao item 7.4 19.83 37.32%163 news 8.38 12.32 68.02%

国内前十大网站主要页面的 domready 时间数据采样 :

大量页面 DomReady 时间在 1.5s 以上 , 在 onload总时间的 50%之后 .所以可以得到结论 :Script Defer 技术异步加载广告脚本不可行 .同时可以得到结论 : 在 DomReady事件中展现会严重拖后广告展现速度 , 影响广告效果

Page 16: 广告前端代码优化

16

async-test.js:var g = 1;

<script> function scriptDomElement(u) {

var a = document.createElement('script'); a.src = u; document.getElementsByTagName('head')[0].appendChild(a);

} scriptDomElement('async-test.js');

</script> <script>

alert(typeof g); // 预期结果是 undefined, Firefox 3.6 弹出 number</script>

Script Dom Element 真异步 !真无阻 ?

玉伯:Script 元素的异步加载属性

a.async = true;

阻滞并不仅仅是平行下载的问题 , 还要区分下载阻滞和运行阻滞 .上面的场景 , 如果 async-test.js比较慢 ,会在下一个 script 节点处导致运行阻滞 .上面代码在给 script增加了 async 属性后 ,除了 Opera 浏览器都做到了真无阻 .

Page 17: 广告前端代码优化

17Script Dom Element 是否稳定 ? 展现速度是否有延迟 ?

Script Dom Element 技术代替静态 script 埋点的另一个关键是其稳定性和速度如何 ?

在复杂的网页上下文环境中 , 浏览器是否会及时的启动异步脚本的加载和执行 ?

我们在 inf.js 内选取部分流量做了一些测试 :

Page 18: 广告前端代码优化

18Script Dom Element 稳定和速度测试

在 CND 上准备 1.js, 2.js, 3.js (Gzip 后 7k) 主要运行一句话 :

alimama_test.callback("1");

方法一 :模拟静态 script 埋点加载脚本

document.write("<script src='1.js'></script>");

方法二 :直接通过 Script Dom Element 加载脚本

scriptDomElement("2.js");

方法三 :用 setTimeout 包裹 ,(同 YUI2 中内部调用了 Y.later 的Y.Get.script 方法 )

window.setTimeout((function(){scriptDomElement("3.js");}),0);

在随机选中的 PV 中让这三个方法按照随机顺序执行分别执行

Page 19: 广告前端代码优化

19Script Dom Element 稳定测试结论

doc.writ

e(PV)

script dom(PV)

script dom/doc.write(

%)

timeout0+script

dom(PV)

timeout0+script dom

/doc.write(%)

IE6 15435 15469 100.22% 15265 98.90%

IE7 4613 4620 100.15% 4549 98.61%

IE8 2021 2019 99.90% 2002 99.06%

非 IE 46284 47940 103.58% 48388 104.55%

综述 :两天的测试中doc.write,scriptdom,timeout0+scriptdom 三种方法收到PV基本一致 ,说明 Script Dom Element基本可靠

紫色区域提示 : 在非 IE 浏览器中 doc.write 表现不佳 , 请求丢失率较高蓝色区域提示 :settimeout0+scriptdom 在 IE 下表现不佳 , 请求丢失率稍高

Page 20: 广告前端代码优化

20Script Dom Element 速度测试结论

速度测试关注两种 script dom 方法与 doc.write 的载入 js 后执行 callback 的时间差

    总 PV<0

(ms)0~100(ms)

100~300(ms

)

>300(ms)

>300(ms)

/总PV(%)

[script dom 响应时间 ] - [doc.write 响应时间 ]

IE6 14813 6821 6003 859 1130 7.63%

IE7 4427 2058 1712 320 337 7.61%IE8 1958 969 723 115 151 7.71%

非 IE4781

91732

42144

3 4452 4600 9.62%

[timeout0+script dom 响应时间 ]

- [doc.write 响应时间 ]

IE6 14764 2660 4405 2971 4728 32.02%

IE7 4388 677 1082 941 1688 38.47%IE8 1955 336 409 474 736 37.65%

非 IE4773

5 5943 23377 8147 1026

8 21.51%

综述 :script dom相比 doc.write有近 8% 的请求慢 300ms 以上 ,待定 .timeout0+script dom则有 35%左右的请求慢 300ms 以上 . 淘汰之 .蓝色区域提示 :有很多时候 domscript 是快于 doc.write 的 , 这和我们让参与测试的三种方法按随机顺序执行相关 .btw: 在性能要求高的情况时考虑优化 YUI2 的 Y.Get.script()?

Page 21: 广告前端代码优化

21Doc.write Script in Iframe无阻滞脚本下载的又一个方案

function dwScriptInIframe(s){

document.write("<iframe id= 'testiframe '></iframe>");

var d = document.getElementById("testiframe").contentWindow.document;

d.write('<!doctype html><html><body><scr' + 'ipt src="'+s+'"></scr'

+ 'ipt></body></html>');

window.setTimeout((function(){d.close();}),0);

}

dwScriptInIframe("4.js");

没有 src 的 iframe 的 location 和父页面相同 , 所以不存在跨域问题 .

iframe 内的脚本下载对父页面其他内容而言是无阻滞的 .

Page 22: 广告前端代码优化

22Doc.write Script in Iframe速度测试结论

  总 PV<0

(ms)0~100

(ms)

100~300

(ms)

300~500

(ms)

500~1000

(ms)

>1000(ms)

>300/ 总

PV(%)

[script dom 时间 ]

- [doc.write 时间 ]

IE6 6045 5547 108 123 267 8.24%

IE7 1827 1639 45 53 90 10.29%

IE8 872 788 19 27 38 9.63%

非 IE1536

8 14074 312 304 678 8.42%

[doc.write script in iframe

时间 ]- [doc.write 时

间 ]

IE6 6029 2596 2448 476 128 123 258 8.44%

IE7 1819 888 588 157 45 44 97 10.23%

IE8 867 469 230 88 23 28 29 9.23%

非 IE1533

21188

8 1956 524 225 216 523 6.29%

综述 :doc.write script in iframe 相比 doc.write同样有 9%的请求慢 300ms 以上 , 也加入备选方案

蓝色区域提示 : 速度差超过 300ms 的基本请求均分在 1000ms左右 .紫色区域提示 :非 IE 浏览器中 ,Doc.write Script in Iframe比 IE 好 , 也比Script Dom Element 要好 .

Page 23: 广告前端代码优化

23Doc.write Script in Iframe技术存在的问题

Google 的提示在一个页面不同 iframe 内载入相同的 JS,其中前一个

请求可能会被 IE取消 (abort);iframe 中由 JS 输出的图片 . 在前进后退或刷新时可

能会被再次请求 , 而此时 JS 输出内容可能已经发生变化 .

其他问题iframe 中 window 变化 ,需要对 JS 进行一些加工iframe 引入额外的性能消耗Firefox 可能无法直接获取 iframe 的引用 ,比如 :

document.write("<scr"+"ipt src='1.js'></scr"+"ipt>")

dwScriptInIframe("4.js");// 代码中 getElementById("testiframe") 执行出错

Page 24: 广告前端代码优化

24Doc.write Script in Iframevs. Script Dom Element

两种技术都能做到无阻滞 .

都能够做到无侵扰 , 不引入 SPOF( 单一故障点 ).

都略有延迟 ,8%左右的反馈慢于直接 doc.write 引入的 JS300ms.

在直接较量中 ,测试收到的 25013次反馈中 ,有14404次Doc.write Script in Iframe先返回 . 略占优 .

如何选择 ? 期待您的建议 !

Page 25: 广告前端代码优化

25插 !测试结论 : 页面 loading过程中的 new Image() 不太靠谱

同样的测试方法 测试三种在页面载入时植入 img 埋点做 PV统计的做法 :

方法 1 : document.write('<img src="1.gif" />');

方法 2 : (new Image()).src="2.gif";

方法 3 : window.setTimeout((function(){(new Image()).src="3.gif";}),0);

 document.write

setTimeout0 + new Image new Image

所有 13190 10757 4591IE6 8422 6349 1160IE7 2487 2150 1541IE8 876 853 856

在复杂的页面环境中 ,IE6,7 下 (new Image).src=”..” 的做法不靠谱 ,IE6 中 85% 的请求服务端收不到 , 即使使用了 setTimeout, 依然有 20%以上的丢失 . 所以不要使用这种写法

Page 26: 广告前端代码优化

26

4 解决使用无阻脚本下载方案引入的其他问题

Page 27: 广告前端代码优化

27

解决广告所在位置问题使用异步下载方案随之而来的第一个问题是广

告出现在哪个位置 ,两种方案 :用户指定广告容器

在发布代码的 in-line脚本中通过document.write 一个锚点做参照 .

<script>

document.write("<a style='display:none !important' id='a1'></a>");

insertAsyncScript("http://adhost/?aid=a1");

</script>

<div id="c1"></div>

<script>

insertAsyncScript("http://adhost/?cid=c1");

</script>

Page 28: 广告前端代码优化

28insertAdjacentHTML插入广告内容

function showAd(sHTML,anchor,container){ if(anchor){ anchor.insertAdjacentHTML("afterEnd",sHTML); }else if(container){ container. insertAdjacentHTML("afterBegin",sHTML); }else{ document.write(sHTML) }}showAd("<a href='1.html'><img src='1.jpg'/></a>", document.getElementById("a1"), document.getElementById("c1"))

insertAdjacentHTML@W3C HTML5 insertAdjacentHTML@MSDN

FireFox 不支持 insertAdjacentHTML! 在服务端根据 UA决定输出内容 .....

Page 29: 广告前端代码优化

29页面 Loading 过程中的 Dom安全操作 (避免 IE 进程崩溃 )

小马:“无法打开 Internet 站点 已终止操作”前因后果

这种错误很可能直接枪毙掉上面的使用 anchor 解决位置问题的方案 .而可能的解决方案类似 YUI针对节点的 onContentReady事件 YUI2 YUI3 :

Executes the callback as soon as the specified element is detected in the DOM with a nextSibling property (indicating that the element's children are available, determine if the content of the available element is safe to modify. )

但这会延缓广告展现速度 , 如果有更好的方案还请不吝赐教 !

Page 30: 广告前端代码优化

30

如何避免客户页面 CSS干扰

Google 是不是为了保证 DOM 安全操作 ,避免前面提到的问题而增加了两层<ins>?

我们的埋点代码 write 出不可见的锚点而没有选择 write 出 div 容器 , 因为输出到客户页面的内容容易受到原页面 CSS干扰 .

处理的方法 :• 使用不常见的 Tag,比如 Google用的<ins>• 使用脚本输出自定义 Tag?

Page 31: 广告前端代码优化

31

1.普通埋点<script src="http://{host}/{path}?i={pid}"></script>

2. 无阻页面下载埋点<script type="text/javascript">

document.write('<a style="display:none!important" id="t-a-{pid}"></a>');

t_s = document.createElement('script');

t_s.id = 'tanx-s-{pid}'; t_s.async = true;

t_s.src = 'http://{host}/{path}?i={pid}';

document.getElementsByTagName('head')[0].appendChild(t_s);

</script>

钻石展位中的优化实战

钻石展位中 , 广告请求中不一定非要包含客户端信息 , 所以普通埋点只是一个固定的到动态广告服务的 script 请求 .提供无阻埋点 , 广告输出时当页面有锚点时 insertAdjacentHTML.

广告技术部提供的广告服务中第一个不引入 SPOF 的产品 .

Page 32: 广告前端代码优化

32

5 inf.js 优化进行时

Page 33: 广告前端代码优化

33

inf.js 优化方案 -- 保守点儿 ?

保留主体框架 , 对于普通 Banner 广告不引入额外的请求 .

将对特殊广告类型 (浮窗 , 对联 ,搜索框 ) 的支持代码移出 inf.js, 在需要时通过异步加载的方式获得支持 .

预期 :• inf.js 大小 Gzip 后 11k降至 Gzip 后 6k左右 .• 对避免长时间阻滞的帮助不大

Page 34: 广告前端代码优化

34

inf.js 改进方案 -- 激进点儿 ?inf.js只包含若干 alimama_ 开头的变量收集和存储 . 大小约2k. 内容固定 , 可以 host 在客户的服务器上 ,或写成 in-line脚本 .同时这个文件可以缓存更长时间 .

在用户不修改发布代码时 , 仅在第一个广告运行时通过无阻方式加载展现用模块 .

预期 :• inf.js 文件 ( 可能产生阻滞的部分 )降至最低 (约 2k), 且可以放置在客户服务器上 ,达到去掉 SPOF( 单一故障点 ) 的目的 . • 首个广告请求加载内容从 11k 下降至 6k左右 ,但多一个脚本请求 .• 在用户不修改发布代码前提下 , 页面第二个广告的加载量仅2k. • 增加请求对广告展示速度稍有影响 , 对收益的影响待评估 .

Page 35: 广告前端代码优化

35

关于广告前端代码组织Mashup 代码的要求 : 小 . 原生 .基本上所有类库都用不上 ......类库提供什么 :• 对 JS 对 DOM功能的补强 (oo,domready…)• 对写法的简化 (lang,selector…)补强部分是 Mashup亟需的 :

OOP 面向对象特性

domReady 最重要事件

modules 模块管理

KISSYcore

miniloader

1.5K

Page 36: 广告前端代码优化

36扯远点 :本地存储 + eval 可行 ?

velocity2010:TCP and the Lower Bound of Web Performance数据在美国东西海岸走一圈要 90ms(侧面说明不是传 10k 要 90ms 那么 1k就只要9ms.)

理论上读取本地数据一定是快的但客户端缓存很小经常被冲刷掉

本地存储+eval 是否会有帮助 ?(BannerMaker会在 Flash 中首先做一些类似尝试 .)

eval 性能问题 :GoogleMap 中测试结论是 eval 对性能的影响可以忽略 .Diffable: only download the deltaseval 安全问题 :本地文件容易被篡改 ,我们没有完全安全的沙箱保证 eval出的代码不对外产生干扰 .

Page 37: 广告前端代码优化

37

6 期望 : 所有第三方内容都能做到不引入 SPOF( 单一故障点 )

Page 38: 广告前端代码优化

38

钻石展位无阻埋点遇到的问题

在钻石展位我们提供了无阻埋点 , 而遇到的问题是 , 当我们需要通过我们的埋点再引入其他第三方通过 JS投放的内容时 (icast视频 ), 引入的代码包含 document.write()... 问题无法解决

所以投放这类广告埋点只能使用原有的埋点模式重写 document.write 方法 , 实现起来很困难 .

(本以为 Google会在 "Don’t Let Third Parties Slow You Down"介绍阻滞变无阻的魔术 ...)

Page 39: 广告前端代码优化

39统一的锚点和容器命名规则无 Doc.write 的第三方内容开发比如我们统一将动态 script 服务指定回调函数名参数定义为

jsonp

比如我们统一的使用ClickTAG 作为传入 Flash 的点击串地址 .

希望容器 ID或者锚点 ID,或者任何能够去除第三方引入 SPOF有效解决方案 , 在第三方开发者当中有统一的规范 .

期望所有第三方开发内容都成为无阻滞 , 无侵扰也无延迟的三无产品 .

最后补充一点 , 更应该形成规范的是第三方内容脚本开发涉及的安全问题 .另一个让人无比头疼的问题 . 好在巨头们 (YAHOO,GOOGLE)已经有所行动 . 这是另一个话题了 .

安全 , 还有今天强调的稳定是第三方内容去追求速度的前提 !

Page 40: 广告前端代码优化

40

Thanks [email protected]

http://twitter.com/leneli