Scripts without async or defer attributes, as well as inline scripts, are fetched and executed immediately, before the browser continues to parse the page. - MDNjavascript
the blocking nature of JavaScript, which is to say that nothing else can happen while JavaScript code is being executed. In fact, most browsers use a single process for both user interface (UI) updates and JavaScript execution, so only one can happen at any given moment in time. The longer JavaScript takes to execute, the longer it takes before the browser is free to respond to user input. - Nicholas C. Zakas「High Performance JavaScript 」html
上面引用兩段話的意思大體是,當瀏覽器解析DOM文檔時,一旦遇到 script 標籤(沒有defer 和 async 屬性)就會當即下載並執行,與此同時瀏覽器對文檔的解析將會中止,直到 script 代碼執行完成。出現這種堵塞行爲一方面是由於瀏覽器的UI渲染,交互行爲等都是單線程操做,另外一方是由於 script 裏面的代碼可能會影響到後面文檔的解析,好比下面的代碼:java
html<script type="text/javascript"> document.write("The date is " + (new Date()).toDateString()); </script>
這個堵塞特性會嚴重的影響用戶體驗,下面是幾種優化方案:shell
</body>
前面。不過更好的方法是下面的非堵塞加載腳本(Nonblocking Scripts)的方法:跨域
Script 有一個 defer 屬性,擁有這個屬性的script代表這個script不會修改DOM,所以這段腳本會在文檔樹所有解析完成後觸發( to be executed after the document has been parsed). 但這個屬性並不被全部的瀏覽器支持。瀏覽器
原理就是使用腳本建立 script 元素,設置 src 需爲要動態添加腳本的 URL,再把這個 script 添加到DOM中。有時咱們須要動態腳本加載完成後再執行某些操做,這就須要咱們在腳本加載完成後添加一個回調函數,這個能夠經過 script 的 onload 事件實現。下面的實現代碼:app
jsfunction loadJS(url, callback){ var script = document.createElement('script'); script.type = 'text/javascript'; if(script.readyState){ // 兼容IE的舊版本 script.onreadystatechange = function(){ if(script.readyState == 'loaded' || script.readyState == 'complete'){ script.onreadystatechange = null; callback(); } } } else{ script.onload = function(){ callback(); } } script.src = url; document.getElementsByTagName('head')[0].appendChild(script); }
有時咱們須要咱們動態加載的腳本按照咱們加載的順序執行,但上面的實現並不能保證這一點,加載的腳本在下載完成後就會當即執行,而不會按照咱們定義的順序。要解決這個問題也不難,能夠參照下面的代碼:async
jsloadJS('a.js', function(){ loadJS('b.js', function(){ loadJS('c.js', function(){ app.init(); }) }) })
當有大量的腳本須要動態添加時,這樣寫也會遇到問題;另外的解決方案是利用一些現成的庫,好比 LABjs函數
原理是利用XMLHttpReques(XHR)對象,動態獲取一段JS代碼,而後插入文檔。
相對其餘方法來講的一個優勢是能夠「懶執行」,也就是JS代碼已經先下載好了並無執行,能夠在須要的來執行(?)(以前的動態腳本在下載後會當即執行)。實現代碼:fetch
jsfunction xhrLoadJS (url, callback){ var xhr = new XMLHttpRequest(); xhr.open('get', url, true); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ var script = document.createElement('script'); script.type = 'text/script'; script.text = xhr.responseText; eval(xhr.responseText); // 執行代碼 document.body.appendChild(script); callback(); } } } xhr.send(null); }
缺點是不能跨域請求