最新博客站點:歡迎來訪javascript
1. 瀏覽器加載css
(1) 同步加載java
在網頁中,瀏覽器加載js文件的方式是經過<script>標籤。以下所示:jquery
//內嵌腳本 <script type="text/javacript"> // code here! </script> //加載外部腳本 <script type="text/javascript src="path/demo.js"></script>
<script>標籤很方便,只要加入後,瀏覽器即可讀取並運行,可是在讀取的時候,瀏覽器是按照<script>標籤的出現順序,讀取Javascript文件,而後當即運行,致使在多個文件相互依賴的狀況下,依賴性最小的文件必須放在最前面,依賴性最大的必須放在最後面,不然代碼會報錯,這一點,想必你們在使用bootstrap的時候都深有體會。另外一方面,瀏覽器採用同步模式加載<script>標籤,也就是說,頁面會等待JavaScript文件加載完成,而後再運行後面的代碼。當存在不少個<script>標籤時,瀏覽器沒法同時讀取,必須讀完一個再讀取另外一個,形成讀取時間大大延長,頁面響應緩慢,影響用戶體驗。同步模式又稱阻塞模式,會阻止瀏覽器的後續處理,中止後續的解析,只有當前加載完成,才能進行下一步操做,因此默認同步執行纔是安全的。但這樣若是js中有輸出document內容、修改DOM、重定向等行爲,就會形成阻塞。因此通常建議把<script>標籤放在<body>結尾處,這樣能減小頁面阻塞。es6
(2)異步加載ajax
爲了解決這一問題,ES5中採用了DOM方法,動態加載JavaScript腳本文件。bootstrap
function loadScript(url) { var script = document.createElement("script"); script.type="text/javascript"; script.src=url; document.body.appendChild(script); }
這種方式經過建立一個新的<script>標籤,並設置其src屬性,異步讀取javacript文件瀏覽器
這樣不會形成頁面阻塞,但會有另外一個問題,若是其餘腳本文件依賴於它,此時沒法保證此腳本何時可以載入完畢。緩存
另外一種加載方式是利用defer和async屬性,使腳本異步加載。渲染引擎遇到這一行命令,就會開始下載外部腳本,但不會等它下載和執行,而是直接執行後面的命令。defer和async的區別是: defer要等到整個頁面在內存中正常渲染結束(DOM結構徹底生成,以及其餘腳本執行完成),纔會執行;async一旦下載完成,渲染引擎就會中斷渲染,執行這個腳本之後,再繼續渲染。即defer是渲染完再執行,async是下載完就執行。另外,若是有多個defer腳本,會按照它們在頁面中出現的順序加載,而多個async腳本是不能保證加載順序的。安全
<script src="path/demo.js" defer></script> <script src="path/demo.js" async></script>
如何選用defer和async。若是使用的script是個模塊,而且不依賴任何其它script文件時使用async;若是該腳本依賴其它script或則被其它script依賴,就使用defer;假若腳本文件很小且被一個async script依賴,就使用內嵌script把該文件放在全部async script前面。
另一種方法是onload事件的異步加載。
(function(){ if(window.attachEvent) { window.attachEvent("load", asyncLoad); } else if(window.addEventListener) { window.addEventListener("load", asyncLoad); } else {
window.onload = asyncLoad;
} var asyncLoad = function() { var script = document.createElement("script"); script.type="text/javascript"; script.async = true; script.src = ('https:'==document.location.protocol ? 'https://ssl' : 'http:www') + '.baidu.com/demo.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(script, s); }; )();
這種方法是把插入script的方法放在一個函數裏面,而後放在window的onload方法裏面執行,這樣就解決了阻塞onload事件的觸發問題。
因爲Javascript的動態性,還有不少異步加載方法:XHR Injection、XHR eval、Script In Iframe、document.write("<script type='text/javascript' src=' '")等;
XHR注入:經過XMLHttpRequest來獲取Javascript,而後建立一個script元素插入到DOM結構中。ajax請求成功後設置script.text爲請求成功後返回的responseText.
var createXHR = function() { var obj; if(window.XMLHttpRequest) obj = new XMLHttpRequest(); else obj = new ActiveObject("Microsoft.XMLHTTP"); return obj; }; var xhr = createXML(); xhr.open("GET", "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js", true); xhr.send(); xhr.onreadystatechange = function() { if(xhr.readyState == 4 && xhr.status == 200) { var script = document.createElement("script"); script.text = xhr.requestText; document.getElementsByTagName("head")[0].appendChild(script); } }
XHR eval(): 與XHR Injection對responseText的執行方式不一樣,直接把responseText放在eval()函數裏面執行。
var createXHR = function() { var obj; if(window.XMLHttpRequest) obj = new XMLHttpRequest(); else obj = new ActiveObject("Microsoft.XMLHTTP"); return obj; }; var xhr = createXML(); xhr.open("GET", "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js", true); xhr.send(); xhr.onreadystatechange = function() { if(xhr.readyState == 4 && xhr.status == 200) { eval(xhr.responseText); $('#btn').click(function() { alert($(this).text()); }); } }
Script In Iframe: 在父窗口插入一個iframe元素,而後再iframe中執行加載JS的操做。
var insertJS = function(){ alert($); }; var iframe = document.createElement("iframe"); document.body.appendChild(iframe); var doc = iframe.contentWindow.document;//獲取iframe中的window doc.open(); doc.write("<script>var insertJS = function(){};<\/script><body onload='insertJS()'></body>"); doc.close();
2. 延遲加載
有些JS代碼在某些狀況下須要使用,並非頁面初始化的時候就要用到。延遲加載就是爲解決這個問題。將JS切分紅許多模塊,頁面初始化時只將事件處理程序添加到UI元素上,而後其它JavaScript代碼的加載延遲到第一次用戶交互或者其餘條件須要用到的時候再加載。相似圖片的懶加載。這樣作的目的是能夠漸進式地載入頁面,儘量快地爲用戶提供目前須要的信息,其他部分的內容能夠在用戶瀏覽該頁面時在後臺載入。
JavaScript的加載分爲兩個部分:下載和執行腳本,異步加載只解決了下載的問題,可是代碼在下載完成後就可能會當即執行,在執行過程當中瀏覽器儲與阻塞狀態,響應不了任何需求。爲了解決JavaScript延遲加載的問題,能夠利用異步加載緩存起來,因此不會當即執行,而後在第一次須要的時候再執行。
第二部份內容的載入能夠用建立動態腳本的形式:
window.onload = function() { var script = document.createElement("script"); script.type="text/javascript"; script.src="demo.js"; document.documentElement.firstChild.appendChild("script"); }
3. 按需加載
能夠經過建立一個require方法,包含須要加載的腳本名稱和附加腳本加載完成後須要執行的回調函數。
function require(file, callback) { var script = document.getElementsByTagName("script")[0]; var newjs = document.createElement("script"); newjs.onload= function() { callback(); }; newjs.src=file; script.parentNode.insertBefore(newjs, script); }
參考:
https://www.jb51.net/article/107680.htm
http://es6.ruanyifeng.com/#docs/module-loader