瀏覽器對javascript的處理主要有2部分:下載和執行javascript
下載在有些瀏覽器中是並行的,有些瀏覽器中是串行的,如IE八、Firefox三、Chrome2都是串行下載的css
執行在全部瀏覽器中默認都是阻塞的,當js在執行時不會進行html解析等其它操做html
javascript有個阻塞特性,當瀏覽器執行javascript代碼時,不能同時作其它任何事情。不管當前javascript代碼是內嵌仍是在外鏈文件中,頁面的下載和渲染都必須停下來等待腳本執行完成。瀏覽器在下載和執行腳本是進出現阻塞的緣由在於,腳本可能會改變頁面或javascript的命名空間,它們對後面頁面內容形成影響。java
瀏覽器在碰到一個引入外部javascript文件的<script>標籤時會停下全部工做來下載並解析執行它,在這個過程當中,頁面渲染和用戶交互徹底被阻塞了。例:git
<html> <head> <title>無標題文檔</title> <link rel="stylesheet" type="text/css" href="styles.css" /> <script type="text/javascript" src="file1.js"></script> <script type="text/javascript" src="file2.js"></script> <script type="text/javascript" src="file3.js"></script> </body> </head> <body> <p>頁面的內容。。。</p> </body> </html>
因爲腳本的阻塞特性,頁面會在3個javascript文件所有下載執行完成後,頁面纔會繼續渲染,把腳本放在頁面頂部會致使明顯延遲,一般表現爲顯示空白頁,用戶沒法瀏覽內容,也沒法與頁面交互。github
ie8+、firefox 3.5+、safari4+、chrome2+都容許並行下載javascript文件,可是在下載的過程當中仍然會阻塞圖片等其它資源的下載。chrome
因爲腳本會阻塞頁面其它資源的下載,所以推薦將javasrcipt儘可能放到body標籤的底部,以減小對整個頁面下載的影響。數組
因爲<script>標籤在下載時會阻塞頁面的渲染,因此減小<script>標籤數量有助於改善這一狀況。建議將多個javascript文件合併爲一個,這樣能夠減小性能的消耗。同時也能夠減小請求的數量。瀏覽器
(參考:在服務端合併和壓縮javascript和CSS文件)app
HTML4 爲<script>標籤訂義了一個defer 屬性,它能使這段代碼延遲執行,然而該屬性只有IE4+支持,所以它不是一個理想的跨瀏覽器解決方案。聲明瞭defer 屬性的script會在DOM加載完成,window.onload 事件觸發前被解析執行:
<html> <head> <title>script defer example</title> </body> </head> <body> <script defer> alert('defer'); </script> <script> alert('script'); </script> <script> window.onload = function(){ alert('load'); } </script> </body> </html>
這段代碼在支持defer屬性的瀏覽器彈出順序是:script、defer、load;不支持defer屬性的瀏覽器彈出的順序是defer、script、load。
<script type="text/javascript"> function loadScript(url, callback) { var script = document.createElement('script') script.type = 'text/javascript'; if (script.readyState) { //for ie script.onreadystatechange = function() { if (script.readyState == 'loaded' || script.readyState == 'complete') { script.onreadystatechange = null; callback(); } }; } else { //other browser script.onload = function() { callback(); }; } script.src = url; document.getElementsByTagName('head')[0].appendChild(script); } </script>
loadscript函數用法
<script type="text/javascript"> //單個文件 loadScript('file1.js', function(){ alert('loaded!'); }); //多個文件 loadScript('file1.js', function(){ loadScript('file2.js',function(){ loadScript('file3.js', function(){ alert('all files loaded!'); }); }); }); </script>
這種技術的重點在於:不管什麼時候啓動下載,文件的下載和執行過程不會阻塞頁面其它進程,你甚至能夠將代碼放在頁面的head區域而不影響頁面的其它部分(下載該文件的http連接除外)。
此技術會先建立一個XHR對象,而後用它下載javascript文件,最後建立動態的script元素將代碼注入到頁面中。
<script type="text/javascript"> var xhr = new XMLHttpRequest(); xhr.open('get', 'file1.js', true); xhr.onreadystatechange = function() { if (xhr.status >= 200 && xhr.status <300 || xhr.status == 304) { var script = document.createElement('script'); script.type = 'text/javascript'; script.text = xhr.responseText; document.body.appendChild(script); } }; xhr.send(null); </script>
這種方法優勢是能夠直接下載javascript代碼但不當即執行。因爲代碼是在<script>標籤以外返回的,所以下載後不會自動執行,這使得是能夠把腳本推遲到你準備好的時候。這種方法的侷限性在於javascript文件必須與所請求的頁面處於相同的域,這意味着javascript文件不能從cdn下載,所以不適合大型網站或項目。
Yahoo!Search工程師Ryan Grove建立的一個通用的延遲加載工具,是loadScript()函數的加強版。
用法示例:
<script type="text/javascript" src="lazyload-min.js"></script> <script type="text/javascript"> LazyLoad.js('the-reset.js', function(){ Application.init(); }); </script>
LazyLoad一樣支持多個javascript文件,並能保證在全部瀏覽器中均可以按正確的順序執行。要加載多個javscript文件,只須要給LazyLoad.js()y方法傳入一個url數組:
<script type="text/javascript" src="lazyload-min.js"></script> <script type="text/javascript"> LazyLoad.js(['first.js', 'the-reset.js'], function(){ Application.init(); }); </script>
項目地址:https://github.com/rgrove/lazyload
LABjs是Kyle Simpson受Steve Sounders的啓發實現的無阻塞加載工具。用法示例:
<script type="text/javascript" src="lab.js"></script> <script type="text/javascript"> $LAB.script('the-reset.js') .wait(function(){ Application.init(); }); </script>
$LAB.script()方法用來定義須要下載的javascript文件,$LAB.wait()用來指定文件下載並執行完畢後所調用的函數。
要下載多個javscript文件,只需鏈式調用另外一個$LAB.script()方法:
<script type="text/javascript" src="lab.js"></script> <script type="text/javascript"> $LAB.script('first.js') .script('the-reset.js') .wait(function(){ Application.init(); }); </script>
LABjs不同凡響的是它管理依賴關係的能力。一般來講,連續的<script>標籤意味着文件逐個下載並按順序執行。
LABjs容許使用wait()方法來指定哪些文件須要等待其它文件。上面的例子中first.js不能保證會在the-reset.js的代碼前執行,爲了確保這一點,必須在第一個script()方法後調用wait():
<script type="text/javascript" src="lab.js"></script> <script type="text/javascript"> $LAB.script('first.js').wait() .script('the-reset.js') .wait(function(){ Application.init(); }); </script>
項目地址:hhttp://labjs.com/
SeaJS 是淘寶玉伯開發的一個遵循 CommonJS 規範的模塊加載框架,可用來輕鬆愉悅地加載任意 javascript 模塊。詳細請參考:http://seajs.com/docs/
Do是豆瓣網kejun開發的一個很輕量的Javascript開發框架。目前do.min.js。它的核心功能是對模塊進行組織和加載。加載採起並行異步隊列的策略,而且能夠控制執行時機。Do能夠任意置換核心類庫,默認是jQuery。
項目地址:https://github.com/kejun/Do