欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

让document.write的广告无阻塞的加载 延迟加载 带document.write 的外部js脚本

shiping1 的头像

让document.write的广告无阻塞的加载

广告代码分析

很多第三方的广告系统都是使用document.write来加载广告,如下面的一个javascript的广告链接。

1<script type="text/javascript" src="http://gg.5173.com/adpolestar/5173/
2;ap=2EBE5681_1BA3_4663_FA3F_E73D2B83FBDC;ct=js;pu=5173;/?"></script>

这个javascript请求返回的是这样的一段代码:

1document.write( "<a href='http://gg.5173.com/adpolestar/wayl/;" +
2"ad=6FF3F844_33E6_86EE_3B96_D94C1CF1AEC4;ap=2EBE5681_1BA3_4663_FA3F_E73D2B83FBDC;" +
3"pu=5173;/?http://www.7bao.com/g/xlsbz/index' target='_blank'><img src='" +
5"border='0' width="132px" height="58px" /></a>" );

这种看似有点二的加载方式,但是你却没办法改造它,因为它本身就是第三方的。并且代码都添加了统计的功能,上面的javascript的广告链接每请求一次都会统计一次,生成的代码也有点击统计的功能,也就是说必须以这种方式来进行加载。

document.write是在页面渲染的时候同步进行的,必须要等javascript代码下载好并且document.write执行完后才 接着渲染后面的内容,如果广告比较多的话,就会导致页面阻塞,尤其是在页面的首屏插好几个图片尺寸比较大的这种广告,那么阻塞情况就相当明显和严重,会让 用户觉得你这个网页很慢。

javascript广告的阻塞加载

重写document.write

为了避免阻塞,就不能让document.write方法在页面渲染的时候执行,必须想办法让javascript的广告代码在DOM树就绪 (DOM ready)之后才执行,但是在DOM树就绪后执行document.write会重新渲染整个页面,这样也是不行的。document.write虽然 是浏览器原生的方法,但是也可以自定义一个方法来覆盖掉原来的方法。在javascript广告代码加载之前,重写document.write,等加载 并执行完再改回来。

javascript广告无阻塞加载

延迟加载javascript代码

上面比较关键的一步,延迟加载javascript代码,如何实现呢?先尝试通过改写script的type属性,比如将type设置成一个自定义 的属性”type/cache”,但这样大部分浏览器(Chrome不会下载)仍然会下载这段代码,但不会执行,在页面渲染的时候下载这么一段代码仍然会 阻塞,通过改写script的type并不能实现真正的延迟加载,最多能实现只加载不执行,而且还存在兼容问题。

将script标签放到textarea标签中,等需要加载的时候再读取textarea的内容,这样可以实现真正的延迟加载script,这个方法要感谢玉伯提出的BigRender(墙外)方案。

1<div>
2<textarea style="display:none">
3<script type="text/javascript" src="http://gg.5173.com/adpolestar/5173/
4;ap=2EBE5681_1BA3_4663_FA3F_E73D2B83FBDC;ct=js;pu=5173;/?"></script>
5</textarea>
6</div>

延迟加载script并重写document.write,下面是代码实现:

01/**
02 * 重写document.write实现无阻塞加载script
03 * @param { Dom Object } textarea元素
04 */
05var loadScript = function( elem ){
06    var url = elem.value.match( /src="([\s\S]*?)"/i )[1],
07        parent = elem.parentNode,
08        // 缓存原生的document.write
09        docWrite = document.write, 
10        // 创建一个新script来加载
11        script = document.createElement( 'script' ),
12        head = document.head ||
13            document.getElementsByTagName( 'head' )[0] ||
14            document.documentElement;
15    
16    // 重写document.write
17    document.write = function( text ){
18        parent.innerHTML = text;
19    };
20 
21    script.type = 'text/javascript';
22    script.src = url;
23    
24    script.onerror =
25    script.onload =
26    script.onreadystatechange = function( e ){
27        e = e || window.event;
28        if( !script.readyState ||
29        /loaded|complete/.test(script.readyState) ||
30        e === 'error'
31        ){
32 
33            // 恢复原生的document.write
34            document.write = docWrite;
35            head.removeChild( script );
36            
37            // 卸载事件和断开DOM的引用
38            // 尽量避免内存泄漏
39            head =         
40            parent =
41            elem =
42            script =
43            script.onerror =
44            script.onload =
45            script.onreadystatechange = null;
46 
47        }
48    }
49    
50    // 加载script
51    head.insertBefore( script, head.firstChild );
52};

图片延迟加载的增强版

实现了无阻塞式的延迟加载javascript广告代码,能否进一步优化?如果广告没在首屏出现,能否像通常的图片的延迟加载一 样来进行延迟加载?答案是肯定的。对我之前写的图片延迟加载的小插件进行扩展,将原来的图片加载方式(替换src)改成上面的loadScript方式加 载就可以实现。当然,仅仅是这样的修改还是会有问题的。如果有多个图片,并且loadScript是同时进行的,而document.write又是全局 的方法,保不准在加载A的时候不影响到B,必须让它们一个个的按顺序加载,加载完A之后才能加载B。

队列控制

为了让javascript广告代码按顺序加载就需要一个队列来控制加载。于是又有了下面这段简单的队列控制代码:

01var loadQueue = [];
02// 入列
03var queue = function( data ){
04    loadQueue.push( data );
05    if( loadQueue[0] !== 'runing' ){
06        dequeue();
07    }
08};
09// 出列  
10var dequeue = function(){
11    var fn = loadQueue.shift();
12    if( fn === 'runing' ){
13        fn = loadQueue.shift();
14    }
15    
16    if( fn ){
17        loadQueue.unshift( 'runing' );
18        fn();
19    }
20};

图片延迟加载插件的使用说明:http://stylechen.com/imglazyload2.html

图片延迟加载的增强版插件下载地址:http://stylechen.com/wp-content/uploads/download/imglazyload.zip

原载于:雨夜带刀's Blog
本文链接:http://stylechen.com/rewrite-documentwrite.html
如需转载请以链接形式注明原载或原文地址。

“让document.write的广告无阻塞的加载”目前已有 18 条评论

  • 都来赚 2012年4月3日11:47

    看完之后,确实有所收获,继续加油~

     
  • xiduoduo365 2012年4月7日23:13

    不能为了看而看,要从中学习经验,呵

     
  • AVENT 2012年4月20日16:31

    你好 来学习下

     
  • www.xiduoduo365.com 2012年4月28日11:36

    看了,有点自己的想法,想切磋切磋!

     
  • Coolicer 2012年5月9日18:01

    学习了,不错。看见document.write就有点恶心

     
  • AVENT 2012年5月14日12:22

    来关注一下,好棒的文章,支持了…

     
  • www.jvdian.com 2012年5月25日17:11

    没有白看,还是有收获的,好!

     
  • flyinhigh 2012年5月27日11:44

    感觉queue和dequeue函数有点问题,这两个函数合到一起就是
    var queue = function( data ){
    loadQueue.push( data );
    if( loadQueue[0] !== ‘runing’ ){
    var fn = loadQueue.shift();
    if( fn === ‘runing’ ){
    fn = loadQueue.shift();
    }

    if( fn ){
    loadQueue.unshift( ‘runing’ );
    fn();
    }
    }
    };
    loadQueue[0]和loadQueue.shift()是相同的,这样的话,fn === ‘runing’这层判断是永远不会进去的。

     
  • 雨夜带刀 2012年5月27日12:19

    @flyinhigh
    队列是一步步执行的,在执行的时候添加一个”runing”的标志以免同时执行其他函数,你再仔细研究研究,或者尝试去掉这个看看会有怎样的结果,这个简单的队列就是jQuery队列的超简化版,原理是一样的。

     
  • maltose 2012年5月28日02:11

    不错,收藏了。

     
  •  

    [...] 最初的想法是重新开发一套广告系统,换一种广告加载方式,但是开发成本太高。最后想到了使用 textarea 来延迟加载广告和 iframe,玉伯提供的这种方法确实挺好用的。textarae 是个好东西,不论是普通的 HTML 代码亦或是 CSS、JavaScript 代码,都可以扔到里面去实现延迟加载。广告图片的优化比较麻烦,我在另一篇文章中有详细的介绍。有了 textarea,很多内容都可以像实现图片延迟加载那样来实行延迟加载,在 TAB 内容中的 iframe 也可以在触发 TAB 菜单时再去加载 iframe。 [...]

     
  • 小新 2012年6月7日03:09

    不能执行google类的js广告代码,希望再次分享可行代码!

     
  •  

    [...] 最初的想法是重新开发一套广告系统,换一种广告加载方式,但是开发成本太高。最后想到了使用 textarea 来延迟加载广告和 iframe,玉伯提供的这种方法确实挺好用的。textarae 是个好东西,不论是普通的 HTML 代码亦或是 CSS、JavaScript 代码,都可以扔到里面去实现延迟加载。广告图片的优化比较麻烦,我在另一篇文章中有详细的介绍。有了 textarea,很多内容都可以像实现图片延迟加载那样来实行延迟加载,在 TAB 内容中的 iframe 也可以在触发 TAB 菜单时再去加载 iframe。 [...]

     
  • alfred lee 2012年6月11日21:46

    领教 学习。

     
  • Franky 2012年10月12日15:13

    这个方案很多情况你都会出问题..

     
  • 雨夜带刀 2012年10月15日09:18

    @Franky
    目前使用没用发现问题,不知道你说的问题具体有哪些?

     
  • AAE全球专递 2013年2月25日20:31

    异步加载也可以。

     

发表评论:


来自 http://stylechen.com/rewrite-documentwrite.html
http://www.ttkc.net/knowlage/759.htm
普通分类: