广告代码分析

很多第三方的广告系统都是使用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请求返回的是这样的一段代码:

1 document.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执行完后才接着渲染后面的内容,如果广告比较多的话,就会导致页面阻塞,尤其是在页面的首屏插好几个图片尺寸比较大的这种广告,那么阻塞情况就相当明显和严重,会让用户觉得你这个网页很慢。

重写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(墙外)方案。

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  */
05 var 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广告代码按顺序加载就需要一个队列来控制加载。于是又有了下面这段简单的队列控制代码:

01 var loadQueue = [];
02 // 入列
03 var queue = function( data ){
04     loadQueue.push( data );
05     if( loadQueue[0] !== 'runing' ){
06         dequeue();
07     }
08 };
09 // 出列  
10 var 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的广告无阻塞的加载的更多相关文章

  1. 关于JavaScript是否会阻塞图片加载

    <?php //1.js.php sleep(5); file_put_contents("tmp.txt", __FILE__.'->'.__LINE__.' -&g ...

  2. 转:JS线程和JS阻塞页面加载的问题

    前几日写了一篇文章,介绍了js阻塞页面加载的问题.当时是通过例子来验证的.今天,我介绍一下浏览器内核,从原理上介绍一下js阻塞页面加载的原因. 浏览器的内核是多线程的,它们在内核制控下相互配合以保持同 ...

  3. PHP + JavaScript + Ajax 实现无刷新页面加载效果

    数据源工厂 Json生成方式1 Json生成方式2 数据搬运工 数据加工师 转换类型 加工展示 结果展示 初始页面 点击按钮之后 总结 今天这个实验的思路就是实现一个无刷新的页面加载效果.具体的思路是 ...

  4. js 利用canvas + flv.js实现视频流 截屏 、本地下载功能实现,兼容火狐,谷歌;canvas截屏跨域问题,无音频视频流加载不显示问题

    项目:物联网监控项目----后台视频流管理(前端实现视频截屏功能) 本文就不同视频源分情况展示: 1 本地视频(项目同目录视频)截屏(canvas.getContext("2d).drawI ...

  5. jquery的 $(function(){ }) = $(document).ready(function(){ }) ,及页面的加载顺序

    document.ready和onload的区别:一.JavaScript文档加载完成事件页面加载完成有两种事件一是ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件) 二.是onloa ...

  6. php+ajax实现无刷新动态加载数据技术

    我们浏览有些网页的时候,当拉动浏览器的滚动条时到页底时,页面会继续自动加载更多内容供用户浏览.这种技术我暂且称它为滚屏加载技术.我们发现很多网站用到这种技术,必应图片搜索.新浪微博.QQ空间等将该技术 ...

  7. 探真无阻塞加载javascript脚本技术,我们会发现很多意想不到的秘密

    下面的图片是我使用firefox和chrome浏览百度首页时候记录的http请求 下面是firefox: 下面是chrome: 在浏览百度首页前我都将浏览器的缓存全部清理掉,让这个场景最接近第一次访问 ...

  8. 通过分析iframe和无阻塞脚本关系能让我们更懂iframe

    在我上篇文章里,我提到一种使用iframe完成无阻塞脚本加载的方式,因为我对iframe的偏见很大,所以上篇文章里我没有展开讨论这个问题. 文章发表后有位网友问了我这样一个问题,下面是他问题的原文,如 ...

  9. 无阻塞加载和defer、async

    无阻塞加载 把js放在head里,浏览器是怎么去执行它的呢,是按顺序加载还是并行加载呢?在旧的浏览器下,都是按照先后顺序来加载的,这就保证了加载的js依赖不会发生问题.但是少部分新的浏览器已经开始允许 ...

随机推荐

  1. Solving the Distal Reward Problem through Linkage of STDP and Dopamine Signaling

    郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! Abstract 在巴甫洛夫式和工具性条件下,奖励通常是在奖励触发动作几秒钟后产生的,从而产生了一个被称为“远端奖励问题”的解释难题:如果 ...

  2. Dubbo直连方式改造

    目录 一.dubbo 服务化最佳实践 1. 分包 2. 粒度 3. 版本 二.改造 dubbo 项目 三.link-interface 1. pom.xml 2. 实体类 3. 公共接口 四.提供者 ...

  3. RedHat 6.8 离线安装Docker (rpm包安装)

    我的环境: [root@localhost ~]# uname -r 2.6.32-642.el6.x86_64 [root@localhost ~]# cat /etc/redhat-release ...

  4. CentOS 7/8上部署Ceph

    Ceph是一个分布式的存储系统,可以在统一的系统中提供唯一的对象.块和文件存储,Ceph的大致组件如下: 1. Ceph监视器(ceph-mon):用来维护集群状态的映射,包括监视器映射,管理器映射, ...

  5. Git-commit-中添加表情

    git commit 中使用表情 我们经常可以在github上看到国外大佬的commit信息中有很多可爱的表情,这是怎么做到的呢? ok,可以这样使用哦:git commit -m '提交信息 :em ...

  6. vps的搭建

    最近一直想自己搭建一款vps使用,但是苦于一直没有时间,直到今天得空,与大家一起分享下. 服务商的选择 因为自己之前在 vultr 上还留有余额(60$呢,好几百块大洋呢),所以我的服务商就选择 vu ...

  7. 10分钟搞定 Java 并发队列好吗?好的

    | 好看请赞,养成习惯 你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it ...

  8. 超级码力编程赛带着6万奖金和1200件T恤向你跑来了~

    炎炎夏日,总是感觉很疲劳,提不起一点精神怎么办?是时候参加一场比赛来唤醒你的激情了!阿里云超级码力在线编程大赛震撼携手全国数百所高校震撼来袭. 它来了,它来了,它带着60000现金和1200件T恤向你 ...

  9. Apache Tika实战

    Apache Tika实战 Tika 简介 Apache Tika 是一个内容分析工具包,可以检测上千种文件类型,并提取它们的元数据和文本.tika在设计上十分精巧,单一的接口使它易于使用,在搜索引擎 ...

  10. 不要再问我 in,exists 走不走索引了

    微信搜『烟雨星空』,获取最新好文. 前言 最近,有一个业务需求,给我一份数据 A ,把它在数据库 B 中存在,而又比 A 多出的部分算出来.由于数据比较杂乱,我这里简化模型. 然后就会发现,我去,这不 ...