Loading JavaScript without blocking has a great effect on page performance optimization, which can effectively reduce the blockage of page load by js. Especially for some advertising js files, since the advertising content may be rich media, it is likely to become a bottleneck for your page loading speed. High-performance JavaScript tells us, classmates, to improve your web page speed, load JS without blocking.
So a code appears.
(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);})();Everyone is familiar with the above. Students who have read the book know the benefits of such non-blocking loading, and the effect is quite good. When such non-blocking scripts encounter general JS advertisements, they will write problems - the ad code appears in HTML but the ad does not display the ad.
Nani? HTML is not rendered to the page?
Let's take a look at the ad js code
The code copy is as follows:
document.write('<img src="http://img.VeVB.COM/logo_small.gif">');
The code is quite simple, just output HTML code in a document.write (I believe that many advertisers’ advertisements are like this). What is the problem with the page not showing advertisements? The problem lies in this document.write. Why? Let’s first look at the definition of document.write.
Definition and usage
The write() method can write HTML expressions or JavaScript code to the document.
Multiple parameters (exp1,exp2,exp3,...) can be listed and they will be appended to the document in order.
method:
One is to use this party to output HTML in the document, and the other is to generate new documents in windows and frameworks outside the windows where the method is called. In the second case, be sure to use the close() method to close the document.
But its principle is to be executed during the page flow input process. Once the page is loaded, document.write() is called again, and document.open() will be called implicitly to erase the current document and start a new document. That is to say, if we use document.write after HTML is loaded, we will eliminate the previous generated html and display the content output from document.write.
In our example, after the page is loaded, the document.write is output in html and will not be executed. I know the problem and the principle, so how to solve this problem?
Asynchronously utilizes ajax, with different lines. Many advertising files are third-party. Under different domain names, there are cross-domain problems, and we cannot control the output of their code. In this case, we thought of a way to rewrite document.write and then rewrite document.write back after the js file is loaded. Look at the code.
The first version loads js ads without blocking:
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(); } };Page call code:
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-adwrap2'); }); loadScript.startLoad(); var loadScript = new LoadADScript('ad3.js','msat-adwrap',function(){ console.log('msat-adwrap3'); }); loadScript.startLoad();Advertising js code
//ad.jsdocument.write('<img src="http://images.cnblogs.com/logo_small.gif">');//ad2.jsdocument.write('<img src="http://www.baidu.com/img/baidu_sylogo1.gif" usemap="#mp">');//ad3.jsdocument.write('<img id="hplogo" src="http://www.google.com/images/srpr/logo3w.png">');The problem with the first version is that when multiple files are called, some problems will arise:
1. Due to the different speed of file loading, some may be loaded first and some may be loaded later, which is unordered, and many times what we need is orderly. For example, we need to load the ad on the first screen first.
2. If you want some advertisements, you need to set some parameters before setting, such as Google adsense
In order to solve these two problems, it is further modified to the final non-blocking js version.
HTML page code:
<!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 source code
/** * Non-blocking ads* @author Arain.Yu */var loadScript = ( function() { var adQueue = [], dw = document.write; //Cache js' own 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(); }; } //Rewrite 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() { //Restore 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(); } } } };}());