Javascript在瀏覽器性能中,這多是全部開發者比較關注的問題,由於Javascript有阻塞的特徵,也就是當Javascript運行的時候,瀏覽器不會處理其餘的任務。可是瀏覽器不可能只運行一個任務,可是同一時間又只能執行單個任務。javascript
無論Javascript代碼是內聯的仍是包含在一個外部文件中的,頁面的下載和解析就必須等待腳本完成,才能繼續向下執行,這樣的緣由是由於腳本的執行可能會從新渲染頁面UI。咱們典型的腳本函數是這樣的。如:css
<html> <head> <title>Script Example</title> </head> <body> <div> <script type="text/javascript"> alert("今天的日期是: " + (new Date()).toDateString()); </script> </div> </body> </html>
當瀏覽器遇到一個<script>標籤時,正如上面的HTML頁面那樣,沒辦法知道Javascript是否是在div標籤中添加或者刪除內容,這樣瀏覽器就中止,運行完當前的腳本,而後再繼續執行下面的內容。固然使用外鏈也是這樣的過程,遇到src外鏈Javascript代碼,瀏覽器也是首先加載這個外部Javascript文件,而後解析運行此Javascript代碼,至於何時執行,徹底要下載此文件須要多久的時間。html
一、腳本的位置java
從HTML4開始,明確之處,一個<script>標籤能夠放在HTML文檔的<head>和<body>標籤中,固然不只限制是連接一個<script>標籤,咱們更多的作法是使用<link>標籤加載外部的Javascript文件,固然了,其中也包含css文件。如:git
<html> <head> <script type="text/javascript" src="file1.js"></script> <script type="text/javascript" src="file2.js"></script> <script type="text/javascript" src="file3.js"></script> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <div> 這是Javascript文件引入的例子。 </div> </body> </html> 可是這樣的寫法理論上是沒有任何問題的,可是這裏就存在了性能和體驗的問題。上面的代碼加載了3個外部文件,每一個文件在加載的過程當中阻塞了頁面的解析,瀏覽器只有等待它們下載並運行了Javascript代碼以後,頁面才能繼續,這咱們在上面已經提到過了。最致命的問題就是,把Javascript文件放在頂部,在加載Javascript文件比較慢的時候會出現空白頁,以致於用戶看不到頁面,更不要說交互網頁,推薦的辦法就是,把全部的Javascript文件,包括外鏈的文件擋在<body>標籤底部位置,減小對整個頁面加載的影響。這裏就不列出例子了。
二、延遲腳本github
這個時候就<script>標籤出現了一個屬性:defer。一個帶有defere屬性的<script>標籤能夠防止在文檔的任何位置,對應的Javascript文件將在<script>被解析時啓動下載,可是代碼不會執行,知道DOM加載完成。當一個帶有defer的Javascript文件被下載時,他不會阻塞瀏覽器的其餘處理過程,因此這些文件能夠與其餘頁面的其餘資源一塊兒並行下載。如:跨域
<html> <head> <title>Script Defer Example</title> </head> <body> <script defer> alert("延遲"); </script> <script> alert("當前"); </script> <script> window.onload = function(){ alert("加載完成") }; </script> </body> </html> ## 標題文字 ##
若是瀏覽器不支持defer屬性,上面的代碼的運行順序是: 延遲-》當前-》加載完成。若是瀏覽器支持defer屬性,那麼運行順序是:當前-》延遲-》加載完成。應該很直觀的就能看出區別。目前defer標籤目前已被全部主流瀏覽器支持數組
另外這不能不提的還有一個屬性:async。用於加載異步腳本,async和defer的相同點是採用並行下載,在下載的過程當中都是不會產生阻塞。區別在於執行時機,async是加載完成後自動執行,,而defer須要等待頁面完成後執行。瀏覽器
三、動態腳本元素緩存
DOM容許使用Javascript動態建立HTML支持的所有內容。如:
var script = document.createElement ("script"); script.type = "text/javascript"; script.src = "file1.js"; document.getElementsByTagName_r("head")[0].appendChild(script);
上面新的<script>元素file.js源文件,此文件被添加到頁面以後馬上開始下載。最重要的一點是這部分代碼的加載和運行不會阻塞其餘頁面處理過程。
這裏有一個封裝方法,能夠實現瀏覽器兼容模式:
function loadScript(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 { //Others script.onload = function(){ callback(); }; } script.src = url; document.getElementsByTagName_r("head")[0].appendChild(script); }
此方法接受兩個參數:url,和一個當Javascript接受完成時觸發的回調函數。最後設置src屬性,再將<script>元素添加到頁面。使用方法爲:
loadScript("file1.js", function(){ alert("文件加載完成!"); });
四、XHR腳本注入
還有一個非阻塞方式活的腳本的方法是使用XMLHttpRequest(XHR)對象加載Javascript腳本,原理就是建立一個XHR對象,而後下載Javascript文件,再用一個動態的<script>元素將Javascript代碼注入頁面。如:
var xhr = new XMLHttpRequest(); xhr.open("get", "file1.js", 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/javascript"; script.text = xhr.responseText; document.body.appendChild(script); } } }; xhr.send(null);
此代碼向服務器發送一個獲取file.js文件的請求,這個請求是GET模式,onreadystatechange事件處理函數檢查readyState是否是4,而後檢查HTTP狀態碼是否是有效的2XX有效的迴應,或者是304的緩存相應。若是收到有效相應,那麼就建立一個新的<script>元素,而後文本屬性設置爲從服務接收到的respinseText字符串。這樣作實際上會chaungjian一個帶有內聯代碼的<sript>元素。一旦新的<script>元素被添加到文檔,代碼將會被執行。
這樣的好處是,能夠下載但不是當即執行Javascript代碼,還有一個好處是兼容性好。
缺點就是不能跨域使用。
五、LazyLoad 類庫
Yahoo! Search的工程師建立了一個更爲通用的LazyLoad庫(參見:http://github.com/rgrove/lazy...)LazyLoad是一個更增強大的loadScript()函數,LazyLoad壓縮後體積很小,用法:
<script type="text/javascript" src="lazyload-min.js"></script> <script type="text/javascript"> LazyLoad.js("file.js", function(){ Application.init(); }); </script>
LazyLoad也能夠同時下載多個Javascript文件,並保證它們在全部瀏覽器上都能以正確的順序遠行,要加載多個Javascript文件,只須要在執行LazyLoad()函數時傳遞一個數組便可,如:
<script type="text/javascript" src="lazyload-min.js"></script> <script type="text/javascript"> LazyLoad.js(["file1.js", "file2.js"], function(){ Application.init(); }); </script>
固然還有其餘類庫,好比 LABjs 這裏就不一一介紹了。
總結
將全部的<script>標籤放置在頁面底部,緊靠body標籤的上方,些方法能夠保證頁面在腳本運行以前完成解析。最好不管Javascript文件是以什麼樣的方式加載的。
講腳本打包,儘可能合併頁面的Javascript文件,文件越少,頁面的加載速度就會越快,不管是內聯的仍是外鏈的Javascript文件。
同步博客地址:http://www.sundexin.com
微博:http://weibo.com/1674378140/p...