首頁 >web前端 >js教程 >重寫document.write實作無阻塞載入js廣告(補充)_javascript技巧

重寫document.write實作無阻塞載入js廣告(補充)_javascript技巧

WBOY
WBOY原創
2016-05-16 16:27:271630瀏覽

無阻塞載入javascript,對於頁面效能最佳化有很大的作用,這樣能有效的減少js對頁面載入的阻塞。特別是一些廣告js文件,由於廣告內容有可能是富媒體,更是很可能成為你頁面加載提速的瓶頸,高性能javascript告訴我們,同學,提升你的網頁速度,就無阻塞地加載JS吧。

於是便有一下程式碼出現。

(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);
})();

上邊都是大家熟悉的,看過書的同學都知道這樣無阻塞加載的好處,效果挺不錯的,當此等無阻塞腳本遇到一般js廣告就來了寫問題——廣告代碼出現在HTML裡面了卻不顯示廣告。

納尼? HTML出來了不渲染到頁面上?

先看看廣告js程式碼

複製程式碼 程式碼如下:

document.write('重寫document.write實作無阻塞載入js廣告(補充)_javascript技巧');

程式碼挺簡單就一個document.write輸出HTML程式碼(相信很多廣告商的廣告都這樣),頁面不顯示廣告問題在哪裡呢? 問題就在這個document.write。為什麼?先w3schools看看document.write的定義很使用吧。

定義與用法
write() 方法可寫入 HTML 運算式或 JavaScript 程式碼給文件。
可列出多個參數(exp1,exp2,exp3,...) ,它們將依序被追加到文件中。

方法:
一是在使用該方在文件中輸出 HTML,另一種是在呼叫該方法的的視窗之外的視窗、框架中產生新文件。在第二種情況中,請務必使用 close() 方法來關閉文件。

但其原理是在頁面流輸入過程中執行,一旦頁面加載完畢,再次調用 document.write(),會隱式地調用 document.open() 來擦除當前文檔並開始一個新的文檔。也就是說如果在HTML載入完後我們再使用document.write會檫除之前產生html,而顯示document.write輸出的內容。

而我們例子中在頁面載入完後在html中輸出document.write,就不會被執行了。問題知道了,原理知道了,那要怎麼解決這個問題呢?

非同步利用ajax,行不同,許多廣告檔案都是第三方的,在不同網域下,有跨域問題,而且不能我們控制其程式碼的輸出。在這種情況下我們想到了一個方法就是重寫掉document.write,在js檔案載入結束後再把document.write重寫回去。看代碼。

第一版無阻塞載入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();
    }
  };

頁面呼叫程式碼:

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="重寫document.write實作無阻塞載入js廣告(補充)_javascript技巧">');

//ad2.js
document.write('<img  src="http://www.baidu.com/img/baidu_sylogo1.gif"    style="max-width:90%"  style="max-width:90%" usemap="#mp" alt="重寫document.write實作無阻塞載入js廣告(補充)_javascript技巧" >');

//ad3.js
document.write('<img alt="Google"    style="max-width:90%" id="hplogo" src="http://www.google.com/images/srpr/logo3w.png"  style="max-width:90%">');

第一版的問題是在多個檔案呼叫的時候,會出現一些問題:

1. 由於檔案載入的速度不一樣,導致可能有些先載入有些後載入,也就是無序的,而且很多時候我們需要的是有序的。例如我們需要先載入第一屏的廣告。

2. 想有些廣告需要前置設定一些參數的,例如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' &#63; 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();
      }
    }
  };
}());
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn