这篇文章主要介绍了用js的document.write输出的广告无阻塞加载的方法,需要的朋友可以参考下

一、广告代码分析

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


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

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


document.write( "<a href='http://gg.5173.com/adpolestar/wayl/;" +
"ad=6FF3F844_33E6_86EE_3B96_D94C1CF1AEC4;ap=2EBE5681_1BA3_4663_FA3F_E73D2B83FBDC;" +
"pu=5173;/?http://www.7bao.com/g/xlsbz/index' target='_blank'><img src='" +
"http://html.5173cdn.com/market/yunyinga/xly132.gif' " +
"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(墙外)方案。


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

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


/**
 * 重写document.write实现无阻塞加载script
 * @param { Dom Object } textarea元素
 */
var loadScript = function( elem ){
 var url = elem.value.match( /src="([sS]*?)"/i )[1],
parent = elem.parentNode,
// 缓存原生的document.write
docWrite = document.write, 
// 创建一个新script来加载
script = document.createElement( 'script' ),
head = document.head ||
 document.getElementsByTagName( 'head' )[0] ||
 document.documentElement;

 // 重写document.write
 document.write = function( text ){
parent.innerHTML = text;
 };

 script.type = 'text/javascript';
 script.src = url;

 script.onerror =
 script.onload =
 script.onreadystatechange = function( e ){
e = e || window.event;
if( !script.readyState ||
/loaded|complete/.test(script.readyState) ||
e === 'error'
){

 // 恢复原生的document.write
 document.write = docWrite;
 head.removeChild( script );

 // 卸载事件和断开DOM的引用
 // 尽量避免内存泄漏
 head =  
 parent =
 elem =
 script =
 script.onerror =
 script.onload =
 script.onreadystatechange = null;

}
 }

 // 加载script
 head.insertBefore( script, head.firstChild );
};

四、图片加载的增强版

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

五、队列控制

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


var loadQueue = [];
// 入列
var queue = function( data ){
 loadQueue.push( data );
 if( loadQueue[0] !== 'runing' ){
dequeue();
 }
};
// 出列 
var dequeue = function(){
 var fn = loadQueue.shift();
 if( fn === 'runing' ){
fn = loadQueue.shift();
 }

 if( fn ){
loadQueue.unshift( 'runing' );
fn();
 }
};


图片加载器请参阅比文:http://www.lovean.com/article/50685.htm 

最新资讯
PayPal斥资40亿美元收购优惠查找应用Honey统计

PayPal斥资40亿美元收

今天,PayPal宣布已斥资约40亿美元收购了Honey Science
索尼成立人工智能组织Sony AI 专注游戏与食品领域

索尼成立人工智能组织

索尼成立了一个名为Sony AI的组织,该组织将会从事人工
虚拟女友亦能摸!《头号玩家》场景实现且不用插电

虚拟女友亦能摸!《头号

无线供电操控,实现毫米级触觉反馈
中国铁塔董事长:已交付11万5G基站 97%现有站址改造

中国铁塔董事长:已交付

对于未来5G建设,他称将坚持资源统筹共享,从供给侧促进5G
部分债权人要求法(tian)院(ping)驳回贾跃亭破产重组申请

部分债权人要求法(tian)院(ping)驳

对此,11月21日,贾跃亭债务处理小组方面表示,如果懒财方面
一图读懂网易Q3财报:净利润47亿元 同比增长109%

一图读懂网易Q3财报:净

网易第三季度净营收146.4亿元,市场预期174.12亿元,去年
最新文章
微信小程序调用天气接口并且渲染在页面过程详解

微信小程序调用天气接

这篇文章主要介绍了微信小程序调用天气接口并且渲染在
Electron + vue 打包桌面操作流程详解

Electron + vue 打包

这篇文章主要介绍了Electron + vue 打包桌面操作流程,
前端Vue项目详解--初始化及导航栏

前端Vue项目详解--初

这篇文章主要介绍了前端Vue项目详解--初始化及导航栏,
ES6 Object方法扩展的应用实例分析

ES6 Object方法扩展的

这篇文章主要介绍了ES6 Object方法扩展的应用,结合实
JS实现给数组对象排序的方法分析

JS实现给数组对象排序

这篇文章主要介绍了JS实现给数组对象排序的方法,结合
基于vue+axios+lrz.js微信端图片压缩上传方法

基于vue+axios+lrz.js

这篇文章主要介绍了基于vue+axios+lrz.js微信端图片压