重寫document.write實現(xiàn)無阻塞加載JS廣告
無阻塞加載javascript,對于頁面性能優(yōu)化有很大的作用,這樣能有效的減少js對頁面加載的阻塞。特別是一些廣告js文件,由于廣告內(nèi)容有可能是富媒體,更是很可能成為你頁面加載提速的瓶頸,高性能javascript告訴我們,同學(xué),提升你的網(wǎng)頁速度,就無阻塞地加載JS吧。
于是便有一下代碼出現(xiàn)。
- (function() {
- var s = document.createElement('script');
- s.type = 'text/javascript';
- s.async = true;
- s.src = 'http://yourdomain.com/script.js';
- var x = document.getElementsByTagName('script')[0];
- x.parentNode.insertBefore(s, x);
- })();
上邊都是大家熟悉的,看過書的同學(xué)都知道這樣無阻塞加載的好處,效果挺不錯的,當此等無阻塞腳本遇到一般js廣告就來了寫問題——廣告代碼出現(xiàn)在HTML里面了卻不顯示廣告。
納尼?HTML出來了不渲染到頁面上?
先看看廣告js代碼
- document.write('<img src="http://images.cnblogs.com/logo_small.gif" alt="Logo">');
代碼挺簡單就一個document.write輸出HTML代碼(相信很多廣告商的廣告都這樣),頁面不顯示廣告問題在哪里呢? 問題就在這個document.write。為什么?先w3schools看看document.write的定義很使用吧。
定義和用法
write() 方法可向文檔寫入 HTML 表達式或 JavaScript 代碼。
可列出多個參數(shù)(exp1,exp2,exp3,...) ,它們將按順序被追加到文檔中。
方法:
一是在使用該方在文檔中輸出 HTML,另一種是在調(diào)用該方法的的窗口之外的窗口、框架中產(chǎn)生新文檔。在第二種情況中,請務(wù)必使用 close() 方法來關(guān)閉文檔。
但其原理是在頁面流輸入過程中執(zhí)行,一旦頁面加載完畢,再次調(diào)用 document.write(),會隱式地調(diào)用 document.open() 來擦除當前文檔并開始一個新的文檔。也就是說如果在HTML加載完后我們再使用document.write會檫除之前生成html,而顯示document.write輸出的內(nèi)容。
而我們例子中在頁面加載完后在在html中輸出document.write,就不會被執(zhí)行了。問題知道了,原理知道了,那怎么解決這個問題呢?
異步利用ajax,行不同,很多廣告文件都是第三方的,在不同域名下,存在跨域問題,而且不能我們控制其代碼的輸出。在這種情況下我們想到了一個辦法就是重寫掉document.write,在js文件加載結(jié)束后再把document.write重寫回去??创a。
***版本無阻塞加載js廣告:
- function LoadADScript(url, container, callback){
- this.dw = document.write;
- this.url = url;
- this.containerObj = (typeof container == 'string'?document.getElementById(container):container);
- this.callback = callback || function(){};
- }
- LoadADScript.prototype = {
- startLoad: function(){
- var script = document.createElement('script'),
- _this = this;
- if(script.readyState){ //IE
- script.onreadystatechange = function(){
- if (script.readyState == "loaded" || script.readyState == "complete"){
- script.onreadystatechange = null;
- _this.finished();
- }
- };
- }else{ //Other
- script.onload = function(){
- _this.finished();
- };
- }
- document.write = function(ad){
- var html = _this.containerObj.innerHTML;
- _this.containerObj.innerHTML = html + ad;
- }
- script.src = _this.url;
- script.type = 'text/javascript';
- document.getElementsByTagName('head')[0].appendChild(script);
- },
- finished: function(){
- document.write = this.dw;
- this.callback.apply();
- }
- };
頁面調(diào)用代碼:
- var loadScript = new LoadADScript('ad.js','msat-adwrap',function(){ console.log('msat-adwrap'); });
- loadScript.startLoad();
- var loadScript = new LoadADScript('ad2.js','msat-adwrap',function(){ console.log('msat-adwrap2'); });
- loadScript.startLoad();
- var loadScript = new LoadADScript('ad3.js','msat-adwrap',function(){ console.log('msat-adwrap3'); });
- loadScript.startLoad();
廣告JS代碼
- //ad.js
- document.write('<img src="http://images.cnblogs.com/logo_small.gif" alt="Logo">');
- //ad2.js
- document.write('<img src="http://www.baidu.com/img/baidu_sylogo1.gif" width="270" height="129" usemap="#mp">');
- //ad3.js
- document.write('<img alt="Google" height="95" id="hplogo" src="http://www.google.com/images/srpr/logo3w.png" width="275">');
***版本的問題是在多個文件調(diào)用的時候,會出現(xiàn)一些問題:
1. 由于文件加載的速度不一樣,導(dǎo)致可能有些先加載有些后加載,也就是無序的,而且很多時候我們需要的是有序的。比如我們需要先加載***屏的廣告。
2. 想有些廣告需要前置設(shè)置一些參數(shù)的,例如google adsense
為了解決這兩個問題好進一步修改成最終無阻塞加載js版本。
HTML頁面代碼:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8" />
- <title>new_file</title>
- <script type="text/javascript" src="loadscript.js"></script>
- </head>
- <body>
- <div id = "msat-adwrap"></div>
- <div id = "msat-adwrap2"></div>
- <script type="text/javascript">
- loadScript.add({
- url:'ad.js',
- container: 'msat-adwrap',
- callback:function(){ console.log('msat-adwrap'); }
- }).add({
- url:'ad2.js',
- container: 'msat-adwrap2',
- callback:function(){ console.log('msat-adwrap2'); }
- }).add({//google adsense
- url:'http://pagead2.googlesyndication.com/pagead/show_ads.js',
- container: 'msat-adwrap',
- init: function(){
- google_ad_client = "ca-pub-2152294856721899";
- /* 250x250 rich */
- google_ad_slot = "3929903770";
- google_ad_width = 250;
- google_ad_height = 250;
- },
- callback:function(){ console.log('msat-adwrap3'); }
- }).execute();
- </script>
- </body>
- </html>
loadscript.js源代碼
- /**
- * 無阻塞加載廣告
- * @author Arain.Yu
- */
- var loadScript = ( function() {
- var adQueue = [], dw = document.write;
- //緩存js自身的document.write
- function LoadADScript(url, container, init, callback) {
- this.url = url;
- this.containerObj = ( typeof container == 'string' ? document.getElementById(container) : container);
- this.init = init ||
- function() {
- };
- this.callback = callback ||
- function() {
- };
- }
- LoadADScript.prototype = {
- startLoad : function() {
- var script = document.createElement('script'), _this = this;
- _this.init.apply();
- if(script.readyState) {//IE
- script.onreadystatechange = function() {
- if(script.readyState == "loaded" || script.readyState == "complete") {
- script.onreadystatechange = null;
- _this.startNext();
- }
- };
- } else {//Other
- script.onload = function() {
- _this.startNext();
- };
- }
- //重寫document.write
- document.write = function(ad) {
- var html = _this.containerObj.innerHTML;
- _this.containerObj.innerHTML = html + ad;
- }
- script.src = _this.url;
- script.type = 'text/javascript';
- document.getElementsByTagName('head')[0].appendChild(script);
- },
- finished : function() {
- //還原document.write
- document.write = this.dw;
- },
- startNext : function() {
- adQueue.shift();
- this.callback.apply();
- if(adQueue.length > 0) {
- adQueue[0].startLoad();
- } else {
- this.finished();
- }
- }
- };
- return {
- add : function(adObj) {
- if(!adObj)
- return;
- adQueue.push(new LoadADScript(adObj.url, adObj.container, adObj.init, adObj.callback));
- return this;
- },
- execute : function() {
- if(adQueue.length > 0) {
- adQueue[0].startLoad();
- }
- }
- };
- }());
原文鏈接:http://www.cnblogs.com/hongcaomao/archive/2012/03/27/javascript_loadad.html
【編輯推薦】