1.defer是IE獨有的一種js異步加載模式,經過src加載的JS會等到文檔解析完纔會執行(document.readyState="interactive")。在script標籤內部也能夠寫入內部JS代碼,可是直接寫入的內部JS代碼會同步執行。javascript
<script src="https://cdn.staticfile.org//vue/2.2.2//vue.min.js" type="text/javascript" charset="utf-8" defer=""defer"> //寫這裏的代碼是同步執行 </script>
2.asyn是W3C的標準異步加載模式,經過src加載的JS要等全部資源加載完之後執行(例如:img)(docuement.readyState="complete"),經過asyn異步加載的外部JS纔會執行,可是asyn模式的script標籤內不能寫JS代碼。css
<script src="https://cdn.staticfile.org//vue/2.2.2//vue.min.js" type="text/javascript" charset="utf-8" async="async"> //這裏不能寫代碼 </script>
由於asyn是W3C標準,IE9以前都不兼容,因此仍是很雞肋。vue
經過插入script標籤的方式實現JS異步加載的原理其實很簡單,直接來代碼:java
<script> function loadScript(url){ var script = document.createElement("script");//新建一個script標籤 script.type="text/javascript";//添加type屬性 //綁定src,實現異步加載 script.src = url; //document.head.appendChild(script);切勿這麼作,IE7和IE5上document沒有head的DOM對象屬性。 var head = document.getElementsByTagName("head")[0]; //插入script標籤 head.appendChild(script);//把script添加到domTree節點中,而且會觸發執行 } loadScript("xxx.js"); </script>
異步加載的JS會何時執行呢?執行會不會阻塞HTML解析呢?基於異步加載方法來一波測試:chrome
<head> .... //這裏是異步加載的代碼 <link rel="stylesheet" type="text/css" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> <script> console.log("告訴我何時執行的"); </script> </head> ----------------------------------------------------------------------------- //這裏是異步加載的外部JS文檔內容 var n =Number(new Date()); var n2 = Number(new Date()); while((n2 - n) < (10*1000)){ n2 = Number(new Date()); console.log(1); }
測試執行的結果:bootstrap
---- 打印39733次1網絡
---- 告訴我何時執行的app
上面的測試結果告訴了咱們,經過插入script異步加載的JS,加載完之後就會當即執行。而且執行的時候會阻塞HTML解析。dom
先來講說我爲何要在中間加入一行外部CSS代碼,咱們知道CSS是異步加載,可是CSS的加載會阻塞內部JS的執行,因此足夠我測試的外部JS加載了。也就是說在內部JS執行前,外部JS確定加載完成了,若是外部JS不會阻塞HTML解析也就不會在內部JS以前執行,可是測試的結果是經過添加script標籤異步加載的外部JS在內部JS以前執行了,因此就說明了這種異步加載JS的方式加載完之後就會當即執行,而且若是HTML沒有解析完就會阻塞HTML解析。異步
那爲何還須要這樣的外部加載方式呢?
咱們知道同步加載JS會阻塞HTML解析,而網絡因素又是很是不可控的因素,若是某個同步加載的外部JS出現網絡不順暢通,就會一直阻塞頁面。若是是一些工具腳本,不須要修改DOM的話,或者是一些不是必定須要的腳本(好比某個特定事件的JS腳本就能夠用這種方式來加載),甚至能夠在頁面渲染完之後經過某個事件觸發來加載它。
既然是異步加載的JS腳本,咱們就有必要知道它何時加載完了,好方便咱們使用,因此下面再來豐富如下這個異步加載JS的方法:
function loadScript(url,callback){
var script = document.createElement("script");//新建一個script標籤
script.type="text/javascript";//添加type屬性
if(script.readyState){
script.onreadystatechange = function(){
//script.readyState發生改變時觸發script.onreadystatechange
if(script.readyState == "complete" || script.readyState == "loaded"){
//script.readyState -->狀態碼初始值是「loading」,根據文件加載進度,值發生改變
//IE經過script.readyState的狀態碼監聽異步文件加載進度
tools[callback]();//採用對象屬性調用須要執行的方法 -- 這裏按須要使用
//看到有前輩說IE7和IE5有時候可能會即有"complete",又有"loaded"狀態,爲了防止萬一能夠在這裏清除監聽事件
script.onreadystatechange = null;
}
}
}else{
script.onload = function(){//script.onload-->表示加載完成之後執行
//除IE之外 Safari chrome firefox opera都兼容
tools[callback]();
}
}
//異步加載文件,必須放在事件添加後面,要否則出現先加載完了,事件函數沒有綁定的的狀況就不會觸發了
script.src = url;
//document.head.appendChild(script);切勿這麼作,IE7和IE5上document沒有head的DOM對象屬性。
var head = document.getElementsByTagName("head")[0];
head.appendChild(script);//把script添加到domTree節點中,而且會觸發執行
}
W3C標準中有onload事件能夠監聽外部腳本是否加載完成,因此IE就須要兼容。
IE的script元素的DOM對象上有readyState屬性記錄外部資源的加載情況,與document對象上的readyState屬性同樣,有四個值:
uninitialized -- 還未開始載入;
loading - 載入中;
interactive - 已加載,文檔與用戶能夠開始交互;
complete - 載入完成;(有些版本是loanded,據說有些版本這兩個狀態都會出現本人沒遇到過)
(tools[callback](),是我測試回調外部腳本的方法,這個不重要,主要看需求,反正這裏就是說明外部JS已經加載完畢了,能夠處理本身要處理的程序了)
凌晨了,晚安。