JS異步加載的三種方式

1、同步加載

  咱們平時使用的最多的一種方式。javascript

<script src="http://yourdomain.com/script.js"></script>
<script src="http://yourdomain.com/script.js"></script>

  同步模式,又稱阻塞模式,會阻止瀏覽器的後續處理,中止後續的解析,只有噹噹前加載完成,才能進行下一步操做。因此默認同步執行纔是安全的。但這樣若是js中有輸出document內容、修改dom、重定向等行爲,就會形成頁面堵塞。因此通常建議把<script>標籤放在<body>結尾處,這樣儘量減小頁面阻塞。css


2、異步加載

  異步加載又叫非阻塞加載,瀏覽器在下載執行js的同時,還會繼續進行後續頁面的處理。主要有三種方式。html

  方法一:也叫Script DOM Element

1 (function(){
2     var scriptEle = document.createElement("script");
3     scriptEle.type = "text/javasctipt";
4     scriptEle.async = true;
5     scriptEle.src = "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js";
6     var x = document.getElementsByTagName("head")[0];
7     x.insertBefore(scriptEle, x.firstChild);        
8  })();

  <async>屬性是HTML5中新增的異步支持。此方法被稱爲Script DOM Element 方法。Google Analytics 和 Google+ Badge 都使用了這種異步加載代碼html5

1 (function(){;
2     var ga = document.createElement('script'); 
3     ga.type = 'text/javascript'; 
4     ga.async = true; 
5     ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 
6     var s = document.getElementsByTagName('script')[0]; 
7     s.parentNode.insertBefore(ga, s); 
8 })();

  可是這種加載方式執行完以前會阻止onload事件的觸發,而如今不少頁面的代碼都在onload時還執行額外的渲染工做,因此仍是會阻塞部分頁面的初始化處理。java

  方法二:onload時的異步加載

 1 (function(){
 2     if(window.attachEvent){
 3         window.attachEvent("load", asyncLoad);
 4     }else{
 5         window.addEventListener("load", asyncLoad);
 6     }
 7     var asyncLoad = function(){
 8         var ga = document.createElement('script'); 
 9         ga.type = 'text/javascript'; 
10         ga.async = true; 
11         ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 
12         var s = document.getElementsByTagName('script')[0]; 
13         s.parentNode.insertBefore(ga, s);
14     }
15 )();

  這種方法只是把插入script的方法放在一個函數裏面,而後放在window的onload方法裏面執行,這樣就解決了阻塞onload事件觸發的問題。jquery

  注:DOMContentLoaded與load的區別。前者是在document已經解析完成,頁面中的dom元素可用,可是頁面中的圖片,視頻,音頻等資源未加載完,做用同jQuery中的ready事件;後者的區別在於頁面全部資源所有加載完畢。ajax

  方法三:其餘方法

  因爲JavaScript的動態性,還有不少異步加載方法: XHR Injection、 XHR Eval、 Script In Iframe、 Script defer屬性、 document.write(script tag)。瀏覽器

  XHR Injection(XHR 注入):經過XMLHttpRequest來獲取javascript,而後建立一個script元素插入到DOM結構中。ajax請求成功後設置script.text爲請求成功後返回的responseText。緩存

 1  //獲取XMLHttpRequest對象,考慮兼容性。
 2     var getXmlHttp = function(){
 3         var obj;
 4         if (window.XMLHttpRequest)
 5             obj = new XMLHttpRequest();
 6         else
 7             obj = new ActiveXObject("Microsoft.XMLHTTP");
 8         return obj;
 9     };  
10     //採用Http請求get方式;open()方法的第三個參數表示採用異步(true)仍是同步(false)處理
11     var xmlHttp = getXmlHttp();
12     xmlHttp.open("GET", "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js", true);
13     xmlHttp.send(); 
14     xmlHttp.onreadystatechange = function(){
15         if (xmlHttp.readyState == 4 && xmlHttp.status == 200){
16             var script = document.createElement("script");
17             script.text = xmlHttp.responseText;
18             document.getElementsByTagName("head")[0].appendChild(script);
19         }
20     }        

  XHR Eval:與XHR Injection對responseText的執行方式不一樣,直接把responseText放在eval()函數裏面執行。安全

 1  //獲取XMLHttpRequest對象,考慮兼容性。
 2     var getXmlHttp = function(){
 3         var obj;
 4         if (window.XMLHttpRequest)
 5             obj = new XMLHttpRequest();
 6         else
 7             obj = new ActiveXObject("Microsoft.XMLHTTP");
 8         return obj;
 9     };  
10     //採用Http請求get方式;open()方法的第三個參數表示採用異步(true)仍是同步(false)處理
11     var xmlHttp = getXmlHttp();
12     xmlHttp.open("GET", "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js", true);
13     xmlHttp.send(); 
14     xmlHttp.onreadystatechange = function(){
15         if (xmlHttp.readyState == 4 && xmlHttp.status == 200){
16             eval(xmlHttp.responseText);
17             //alert($);//能夠彈出$,代表JS已經加載進來。click事件放在其它出會出問題,應該是還沒加載進來
18             $("#btn1").click(function(){
19                 alert($(this).text());
20             });
21         }
22     }        

  Script In Irame:在父窗口插入一個iframe元素,而後再iframe中執行加載JS的操做。

1  var insertJS = function(){alert(2)};
2     var iframe = document.createElement("iframe");
3     document.body.appendChild(iframe);
4     var doc = iframe.contentWindow.document;//獲取iframe中的window要用contentWindow屬性。
5     doc.open();
6     doc.write("<script>var insertJS = function(){};<\/script><body onload='insertJS()'></body>"); 7  doc.close();

  GMail Mobile:業內JS內容被註釋,因此不會執行,在須要的時候,獲取script中的text內容去掉註釋,調用eval()執行。

1 <script type="text/javascript"> 
2     /* 
3  var ... 4     */ 
5     </script>

HTML5新屬性:async和defer屬性

  defer屬性:IE4.0就出現。defer屬聲明腳本中將不會有document.write和dom修改。瀏覽器會並行下載其餘有defer屬性的script。而不會阻塞頁面後續處理。注:全部的defer腳本必須保證按順序執行的。

  <script type="text/javascript" defer></script>

  Firefox 3.六、Opera 10.五、IE 9和最新的Chrome和Safari都支持async屬性。能夠同時使用async和defer,這樣IE 4以後的全部IE都支持異步加載。

  沒有async屬性,script將當即獲取(下載)並執行,期間阻塞了瀏覽器的後續處理。若是有async屬性,那麼script將被異步下載並執行,同時瀏覽器繼續後續的處理。


3、延遲加載

  有些JS代碼在某些狀況在須要使用,並非頁面初始化的時候就要用到。延遲加載就是爲了解決這個問題。將JS切分紅許多模塊,頁面初始化時只加載須要當即執行的JS,而後其它JS的加載延遲到第一次須要用到的時候再加載。相似圖片的延遲加載。

  JS的加載分爲兩個部分:下載和執行。異步加載只是解決了下載的問題,可是代碼在下載完成後就會當即執行,在執行過程當中瀏覽器處於阻塞狀態,響應不了任何需求。

  解決思路:爲了解決JS延遲加載的問題,能夠利用異步加載緩存起來,但不當即執行,須要的時候在執行。如何進行緩存呢?將JS內容做爲Image或者Object對象加載緩存起來,因此不會當即執行,而後在第一次須要的時候在執行。

  

  1:模擬較長的下載時間:

    利用thread讓其sleep一段時間在執行下載操做。

  2:模擬較長的JS代碼執行時間   

    var start = Number(new Date());

    while(start + 5000 > Number(new Date())){//執行JS}

    這段代碼將使JS執行5秒才完成!


JS延遲加載機制(LazyLoad):簡單來講,就是在瀏覽器滾動到某個位置在觸發相關的函數,實現頁面元素的加載或者某些動做的執行。如何實現瀏覽器滾動位置的檢測呢?能夠經過一個定時器來實現,經過比較某一時刻頁面目標節點位置和瀏覽器滾動條高度來判斷是否須要執行函數。
相關文章
相關標籤/搜索