JavaScript のノンブロッキング読み込みは、ページのパフォーマンスを最適化する上で大きな役割を果たし、ページ読み込み時の js のブロックを効果的に軽減できます。特に一部の広告 JS ファイルの場合、広告コンテンツがリッチ メディアである可能性があるため、ページの読み込み速度のボトルネックになる可能性があります。高パフォーマンスの JavaScript では、Web ページの速度を向上させるために、ブロックせずに 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 コードを見てください
コードは非常に単純で、HTML コードを出力する document.write だけです (多くの広告主の広告がこれに似ていると思います)。ページに広告が表示されないのはなぜですか? 問題はこの document.write にあります。なぜ?まず、w3schools を見て、document.write の定義がどのように非常に役立つかを見てみましょう。
定義と使用法
write() メソッドは、HTML 式または JavaScript コードをドキュメントに書き込みます。
複数のパラメータ (exp1、exp2、exp3、...) をリストすることができ、それらは順番にドキュメントに追加されます。
方法:
1 つは、このメソッドを使用してドキュメント内に HTML を出力する方法であり、もう 1 つは、このメソッドが呼び出されたウィンドウ以外のウィンドウまたはフレームに新しいドキュメントを生成する方法です。 2 番目のケースでは、必ず close() メソッドを使用してドキュメントを閉じます。
しかし、原則として、ページがロードされると、document.write() を再度呼び出すと、暗黙的に document.open() が呼び出され、現在のドキュメントが消去され、新しいドキュメントが開始されます。つまり、HTMLをロードした後に再度document.writeを実行すると、以前に生成されたHTMLは削除され、document.writeで出力された内容が表示されます。
この例では、ページがロードされた後に document.write が HTML で出力された場合、それは実行されません。問題と原理はわかったので、この問題をどのように解決すればよいでしょうか?
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="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">');
最初のバージョンの問題は、複数のファイルが呼び出されるときにいくつかの問題が発生することです。
1. ファイルの読み込み速度が異なるため、最初に読み込まれるものもあれば、後で読み込まれるものもあり、これは無秩序であり、多くの場合、必要なものは整然としています。たとえば、最初に最初の画面の広告を読み込む必要があります。
2. Google Adsense など、一部の広告では事前にパラメータを設定する必要があると思います
これら 2 つの問題を解決するために、最終的なノンブロッキング読み込み 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(); } } }; }());