1. 程式人生 > >js(十六)---非同步載入

js(十六)---非同步載入

非同步載入

說到非同步,那麼什麼叫做非同步載入呢? 剛開始的時候,也簡單的說聊了一下什麼叫做非同步。大致的因該知道非同步是用來做什麼的了,就是為了充分了利用js引擎,是頁面更快的載入而已。那麼具體如何實現非同步的,又為什麼要使用非同步操作,那麼接下來在詳細的說明一下。 在正式的說明之前,先說一個小的知識點。

JSON

大家可能知道JSON是什麼東西,它是以資料的一種形式,用來作為資料的傳輸的。 資料傳輸的方式:xml和JSON。 xmlhtml的模板,自定義標籤名作為資料名來傳輸資料,書寫是比較麻煩的,現在大部分的都在用json格式的。 json是資料傳輸的一種格式,它是以物件為模板(其實它就是一個物件而已,但是還是有一些區別的,物件只能在班底上,而json是傳遞資料用的。)
當我們把資料給傳輸過去的時候,資料只是一種json的格式,必須轉化成物件的模式,在本地才能使用的。那麼就用到了JSON上的兩種方法了(JSON.parse()、JSON.stringfy())
var obj1 = {
            name: "si",
            age: 18
        }
        var string1 = JSON.stringify(obj1);  
        var string2 = JSON.parse(string1)
        console.log(string1)//將物件轉化成JSON格式的
        console.log(string2)//將JSON格式的轉化成物件
經過這兩種方法的轉化,我們可以接受後臺給的資料,也能將資料傳給後臺,實現了資料的互動。

JS非同步載入部分

我們應該知道script標籤有阻塞DOM解析的作用,只有script下載結束之後並且等執行結束後,才能進行下面的DOM解析。 如果這樣的話就會導致一些不便了:本身這一塊的功能不是太大,有可能在使用者開啟的時候根本就用不到的,結果就給阻塞在這裡,導致以後的頁面載入不出來。如果網不好的情況下,就會導致一個卡頓,可能會看著很不舒服的。那麼我們得有辦法來解決這個問題呀,我們就分析一下這個原因: DOMTree是來解析DOM來用的,當頁面在解析DOM的時候,中間突然加上一個script標籤,這樣會導致DOMTree和CSSTree解析暫時停下來,先把script標籤載入完畢之後,在進行接下的操作。這個時候我們就要加入一些東西了,讓這個標籤非同步載入或者是說按需載入,就會解決這個問題了。
之前我們在寫demo時候都把script標籤都寫在後面,這樣就沒有上面的影響了。 那呢接下來,就介紹一下js的非同步載入: 1.defer 我們在script標籤的行間寫一個defer=“defer”或者直接寫defer,就可以讓這個script變成非同步載入了。但是這種非同步只是針對下載方面,只有等DOMTree全部解析完成(不包括下載完裡面的資源)後才會非同步執行。而且這個方法只有IE和一些高版本的firefox和chrome可以用
 
<script type="text/javascript" defer>
	function test(){
          console.log('123');
  }
</script>
當然裡面也可以外部引入,用個src,這樣就可以引入外部檔案的js了。 IE6和IE7的非同步載入最多隻能有2個,當多餘兩個的時候必須等前兩個載入完才會載入第三個。 所有defer的js程式碼都保證按照順序執行
defer(延遲)是html4.0中定義的,該屬性使得瀏覽器能延遲指令碼的下載,等document文件載入和解析完成後,按照他們在文件中出現順序再去下載解析。也就是說defer屬性的<script>就類似於將<script>放在body底部的效果,會在document的DOMContentLoaded事件之前執行。 2.async非同步載入
async(非同步)是HTML5新增的屬性,該屬性的作用是讓瀏覽器能並行下載指令碼且不阻塞瀏覽器的文件解析和渲染,下載完成後指令碼立即執行,可能無序執行,取決於下載完成的時間,這個非同步相對來說比較強大一些,但是相容s性的問題,必須支援html5的瀏覽器才能使用這個屬性的。
 
<script type="text/javascript" async></script>
 
既然說到這個了,那麼就說一下它們的區別吧:

(1)每一個async屬性的指令碼一旦載入完畢就會立刻執行,一定會在window.onload之前執行,但可能在document的DOMContentLoaded之前或之後執行。不保證按照指定它們的順序來執行,如果JS有依賴性就要注意了。指定非同步指令碼的目的是不讓頁面等待兩個指令碼下載和執行,從而非同步載入頁面其他內容,因此,建議非同步指令碼不要在載入期間修改DOM。

(2)每一個defer屬性的指令碼都是在文件元素完全載入後,一般會按照原本的順序執行,同時一般會在document的DOMContentLoaded之前執行,相當於window.onload,但應用上比 window.onload 更靈活!實際上,defer 更接近於DomContentLoad。事實上,延遲指令碼不一定會按順序執行,也不一定會在DOMContentLoaded事件觸發之前執行,因此最好只包含一個延遲指令碼。


DOMContentLoaded與load的區別。前者是在document已經解析完成,頁面中的dom元素可用,但是頁面中的圖片,視訊,音訊等資源未載入完,作用同jQuery中的ready事件;後者的區別在於頁面所有資源全部載入完畢。
那麼問題就來了,defer(延遲)這個屬性跟window.onload,到了最後再進行載入頁面,不會阻塞onload,但是,這個async屬性,如果非同步載入的沒有載入完,會導致了,onload無法觸發,因此會阻塞。
解決方法:
  (function(){
	if(window.attachEvent){
    	window.attachEvent("load", asyncLoad);
    }else{
    	window.addEventListener("load", asyncLoad);
    }
    var asyncLoad = function(){
    	var ga = document.createElement('script'); 
        ga.type = 'text/javascript'; 
        ga.async = true; 
        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 
        var s = document.getElementsByTagName('script')[0]; 
        s.parentNode.insertBefore(ga, s);
    }
    }

)();

這個方法先等到文件解析完成之後,在觸發onload,在進行非同步載入js,不會影響頁面的卡頓了,這樣也優化了介面,提高了效能。 3.動態建立script標籤

在沒有定義defer和async之前,非同步載入的方式是動態建立script通過window.onload方法確保頁面載入完畢再將script標籤插入到DOM中。

function addScriptTag(src){  
    var script = document.createElement('script');  
    script.setAttribute("type","text/javascript");  
    script.src = src;  
    document.body.appendChild(script);  
}  
window.onload = function(){  
    addScriptTag("js/index.js");  
}  


這個動態建立之後,一定要把這個標籤放在onload裡面,剛才也說到了,如果不放在這裡面,會阻塞頁面也就達不到我們想要的結果了。

今天對非同步操作又有了深刻的理解,同時也看了一些大神們寫的資料。感覺自己以前瞭解的還是不夠多。