广告代码分析
很多第三方的广告系统都是使用document.write来加载广告,如下面的一个javascript的广告链接。
1 | <script type= "text/javascript" src="http: |
2 | ;ap=2EBE5681_1BA3_4663_FA3F_E73D2B83FBDC;ct=js;pu=5173;/?"></script> |
这个javascript请求返回的是这样的一段代码:
2 | "ad=6FF3F844_33E6_86EE_3B96_D94C1CF1AEC4;ap=2EBE5681_1BA3_4663_FA3F_E73D2B83FBDC;" + |
5 | "border='0' width=" 132px " height=" 58px " /></a>" ); |
这种看似有点二的加载方式,但是你却没办法改造它,因为它本身就是第三方的。并且代码都添加了统计的功能,上面的javascript的广告链接每请求一次都会统计一次,生成的代码也有点击统计的功能,也就是说必须以这种方式来进行加载。
document.write是在页面渲染的时候同步进行的,必须要等javascript代码下载好并且document.write执行完后才 接着渲染后面的内容,如果广告比较多的话,就会导致页面阻塞,尤其是在页面的首屏插好几个图片尺寸比较大的这种广告,那么阻塞情况就相当明显和严重,会让 用户觉得你这个网页很慢。
重写document.write
为了避免阻塞,就不能让document.write方法在页面渲染的时候执行,必须想办法让javascript的广告代码在DOM树就绪 (DOM ready)之后才执行,但是在DOM树就绪后执行document.write会重新渲染整个页面,这样也是不行的。document.write虽然 是浏览器原生的方法,但是也可以自定义一个方法来覆盖掉原来的方法。在javascript广告代码加载之前,重写document.write,等加载 并执行完再改回来。
延迟加载javascript代码
上面比较关键的一步,延迟加载javascript代码,如何实现呢?先尝试通过改写script的type属性,比如将type设置成一个自定义 的属性”type/cache”,但这样大部分浏览器(Chrome不会下载)仍然会下载这段代码,但不会执行,在页面渲染的时候下载这么一段代码仍然会 阻塞,通过改写script的type并不能实现真正的延迟加载,最多能实现只加载不执行,而且还存在兼容问题。
将script标签放到textarea标签中,等需要加载的时候再读取textarea的内容,这样可以实现真正的延迟加载script,这个方法要感谢玉伯提出的BigRender(墙外)方案。
2 | <textarea style= "display:none" > |
3 | <script type= "text/javascript" src="http: |
4 | ;ap=2EBE5681_1BA3_4663_FA3F_E73D2B83FBDC;ct=js;pu=5173;/?"></script> |
延迟加载script并重写document.write,下面是代码实现:
05 | var loadScript = function( elem ){ |
06 | var url = elem.value.match( /src= "([\s\S]*?)" /i )[1], |
07 | parent = elem.parentNode, |
09 | docWrite = document.write, |
11 | script = document.createElement( 'script' ), |
12 | head = document.head || |
13 | document.getElementsByTagName( 'head' )[0] || |
14 | document.documentElement; |
17 | document.write = function( text ){ |
18 | parent.innerHTML = text; |
21 | script.type = 'text/javascript' ; |
26 | script.onreadystatechange = function( e ){ |
27 | e = e || window. event ; |
28 | if ( !script.readyState || |
29 | /loaded|complete/.test(script.readyState) || |
34 | document.write = docWrite; |
35 | head.removeChild( script ); |
45 | script.onreadystatechange = null ; |
51 | head.insertBefore( script, head.firstChild ); |
图片延迟加载的增强版
实现了无阻塞式的延迟加载javascript广告代码,能否进一步优化?如果广告没在首屏出现,能否像通常的图片的延迟加载一 样来进行延迟加载?答案是肯定的。对我之前写的图片延迟加载的小插件进行扩展,将原来的图片加载方式(替换src)改成上面的loadScript方式加 载就可以实现。当然,仅仅是这样的修改还是会有问题的。如果有多个图片,并且loadScript是同时进行的,而document.write又是全局 的方法,保不准在加载A的时候不影响到B,必须让它们一个个的按顺序加载,加载完A之后才能加载B。
队列控制
为了让javascript广告代码按顺序加载就需要一个队列来控制加载。于是又有了下面这段简单的队列控制代码:
03 | var queue = function( data ){ |
04 | loadQueue.push( data ); |
05 | if ( loadQueue[0] !== 'runing' ){ |
10 | var dequeue = function(){ |
11 | var fn = loadQueue.shift(); |
12 | if ( fn === 'runing' ){ |
13 | fn = loadQueue.shift(); |
17 | loadQueue.unshift( 'runing' ); |
图片延迟加载插件的使用说明:http://stylechen.com/imglazyload2.html
图片延迟加载的增强版插件下载地址:http://stylechen.com/wp-content/uploads/download/imglazyload.zip
“让document.write的广告无阻塞的加载”目前已有 18 条评论