高效能的JavaScript--載入和執行

來源:互聯網
上載者:User

寫在前面JavaScript在瀏覽器中的效能,可認為是開發人員所要面對的最重要的可用性的問題,此問題因JavaScript的阻塞特徵而複雜,也就是說JavaScript運行時其他的事情不能被瀏覽器處理,事實上,大多數瀏覽器使用單進程處理UI更新和JavaScript運行等多個任務,而同一時間只能有一個任務被執行。JavaScript運行了多長時間,那麼瀏覽器空閑下來響應使用者輸入之前的等待時間就有多長。 從基本層面說,這就意味著<script>標籤的出現使整個頁面因指令碼解析、運行出現等待。不論實際的JavaScript代碼是內聯的還是包含在一個不相干的外部檔案中頁面下載和解析過程必須停下,等待指令碼完成這些處理,然後才能繼續,也是頁面生命週期必不可少的部分,因為指令碼可能在運行過程中修改頁面內容。 在載入JavaScript過程中,頁面解析和使用者互動是被完全阻塞的。 指令碼位置 HTML 4 文檔指出,一個<script>標籤可以放在 HTML文檔的 <head> 或者<body>標籤中,可以在其中多次出現。傳統上,<script> 標籤用於載入外部JavaScript 檔案。<head>部分除此類代碼外,還包含 <link>標籤用於載入外部css檔案和其他頁面中介軟體。也就是說,最好把風格和行為所依賴的部分放在一起,首先載入他們,使他們可以得到正確的外觀和行為。 例如: 複製代碼 1 <html>  2 <head> 3 <title>Script Example</title> 4 <-- Example of ineffi cient script positioning --> 5 <script type="text/javascript" src="file1.js"></script> 6 <script type="text/javascript" src="file2.js"></script> 7 <script type="text/javascript" src="file3.js"></script> 8 <link rel="stylesheet" type="text/css" href="styles.css"> 9 </head>10 <body>11 <p>Hello world!</p>12 </body>13 </html>複製代碼 雖然這些代碼看起來沒什麼問題,但是在〈head〉部分載入了三個JavaScript檔案。每個〈script〉標籤阻塞了頁面解析過程,直到完整的下載並運行了外部JavaScript代碼之後,頁面才能繼續進行。在瀏覽器沒有遇到〈body〉標籤之前,不會渲染頁面的任何部分。 把指令碼放在頁面的頂端,將會導致一個可以察覺的延遲,通常表現為:頁面開啟一片白,使用者不能閱讀和操作。   ,當第一javas檔案開始下載時,阻塞了其他檔案下載。進一步當第一個檔案下載完成之後和第二個檔案下載之前有一個延時,是第一個檔案完全運行所需要的時間。 解決這個問題推薦的辦法是:將所有<script> 標籤放在儘可能接近<body> 標籤的底部位置,盡量減少對整個頁面下載的影響。 如: 複製代碼 1 <html> 2 <head> 3 <title>Script Example</title> 4 <link rel="stylesheet" type="text/css" href="styles.css"> 5 </head> 6 <body> 7 <p>Hello world!</p> 8 <-- Example of recommended script positioning --> 9 <script type="text/javascript" src="file1.js"></script>10 <script type="text/javascript" src="file2.js"></script>11 <script type="text/javascript" src="file3.js"></script>12 </body>13 </html>複製程式碼群組成指令碼 由於每個<script>標籤下載時阻塞頁面解析過程,所以限制頁面的<script>總數也是可以改善效能。這個規則對內聯指令碼和外部指令碼同樣適用。每當頁面解析碰到一個<script>標籤時,緊接著有一段時間用於代碼執行。最小化這些延遲時間可以改善頁面的整體效能。 每個HTTP請求都會產生額外的效能負擔,下載一個100KB的檔案比下載4個25KB的檔案要快。總之,減少引用外部檔案的數量。典型的,一個大型網站或者網頁應用需要多次請求JavaScript檔案。你可以將這些檔案整合成一個檔案,只需要一個<script>標籤引用,就可以減少效能損失。 非阻塞指令碼 JavaScript傾向於阻塞瀏覽器某些處理過程,如HTTP請求和介面重新整理,這是開發人員面臨的最顯著的效能問題。保持JavaScript檔案短小,並限制HTTP請求的數量,只是建立反應迅速的網頁應用的第一步。一個應用程式所包含的功能越多,所需要的JavaScript代碼就越大,保持源碼短小並不總是一種選擇。儘可能下載一個大JavaScript檔案只產生一次HTTP請求。卻會鎖住瀏覽器一大段時間。為避開這種情況,你需要向頁面中逐步添加JavaScript,某種程度上說不會阻塞瀏覽器。 非阻塞指令碼的秘密在於,等頁面載入之後,再載入JavaScript源碼。從技術角度上講,這意味著在window的load事件發出之後下載代碼。有幾種方法可以實現這種效果。 1.延期指令碼 HTML4為<script>標籤定義了一個擴充屬性:defer。這個defer屬性指明元素中所包含的指令碼不打算修改DOM,因此代碼可以稍後執行(適用於IE4以上瀏覽器) <script type="text/javascript" src="file1.js" defer></script>帶有該屬性的JavaScript檔案在<script>被解析時啟動下載,但代碼不會被執行,直到DOM載入完成,它不會阻塞瀏覽器的其他處理過程,所以這些檔案可以與頁面的其他資源一起並行下載。2.動態指令碼元素 文件物件模型dom允許使用JavaScript動態建立HTML的幾乎全部文檔內容。其根本在於<script>元素與頁面其他元素沒有什麼不同。 當檔案使用動態指令碼節點下載時,返回的代碼通常立即執行。當指令碼“自運行”類型時這一機制運行正常,但是如果指令碼只包含頁面其他指令碼調用的的介面,則會帶來問題。這種情況下,你需要跟蹤指令碼下載完成並準備妥善的情況。IE 會發出一個readystatechange事件。<script>元素有一個readyState屬性,它的值隨著外部下載的過程而改變。readyState有5種取值。uninitialized       預設狀態loading             開始下載interactive        下載完成但尚不可用complete          所有資料都已經準備好 下面封裝一個函數來實現JavaScript檔案的動態載入: 複製代碼 1 function loadScript (url, callback){ 2 var script = document.createElement ("script") 3 script.type = "text/javascript"; 4 if (script.readyState){ //IE 5 script.onreadystatechange = function(){ 6 if (script.readyState == "loaded" ||  script.readyState == "complete"){ 7 script.onreadystatechange = null; 8 callback(); 9 }10 };11 } else {  //Others12 script.onload = function(){13 callback();14 };15 }16 script.src = url;17 document.getElementsByTagName_r("head")[0].appendChild(script);18 }複製代碼使用方法: 1 loadScript("file1.js", function(){2 alert("File is loaded!");3 }); 使檔案按順序載入: 複製代碼1 loadScript("file1.js", function(){2 loadScript("file2.js", function(){3 loadScript("file3.js", function(){4 alert("All files are loaded!");5 });6 });7 });複製代碼3.XHR指令碼注入使用XMLHttpRequest(XHR)對象將指令碼注入到頁面中。此技術首先建立一個XHR對象,然後下載javas檔案,接著用一個動態<script>元素將javas代碼注入頁面。 複製代碼 1 var xhr = new XMLHttpRequest(); 2 xhr.open("get", "file1.js", true); 3 xhr.onreadystatechange = function(){ 4 if (xhr.readyState == 4){ 5 if (xhr.status >= 200 && xhr.status < 300 | | xhr.status == 304){ 6 var script = document.createElement ("script"); 7 script.type = "text/javascript"; 8 script.text = xhr.responseText; 9 document.body.appendChild(script);10 }11 }12 };13 xhr.send(null);複製代碼此代碼向伺服器發送一個擷取file1.js檔案的GET請求。onreadystatechange事件處理函數檢查readyState是不是4,然後檢查HTTP狀態代碼是不是有效(2XX表示有效回應,304表示一個緩衝響應)。如果收到一個有效響應,那麼就建立一個新的<script>元素,將它的文字屬性設定為從伺服器接受到的resposeText字串。這樣做實際上會建立一個帶有內聯代碼的<script>元素。一旦新的<script>元素被添加到文檔,代碼將被執行並準備使用。 這種方法的主要優點是,您可以下載不立即執行的 JavaScript 代碼。由於代碼返回在<script>標籤之外(換句話說不受<script>標籤約束),它下載後不會自動執行,這使得您可以延遲執行,直到一切都準備好了。另一個優點是,同樣的代碼在所有現代瀏覽器中都不會引發異常。  此方法最主要的限制是:JavaScript 檔案必須與頁面放置在同一個域內,不能從 CDN 下載(CDN 指”內容投遞網路(Content Delivery Network)”,所以大型網頁通常不採用 XHR 指令碼注入技術。 總結減少 JavaScript 對效能的影響有以下幾種方法: 將所有的<script>標籤放到頁面底部,也就是</body>閉合標籤之前,這能確保在指令碼執行前頁面已經完成了渲染。儘可能地合并指令碼。頁面中的<script>標籤越少,載入也就越快,響應也越迅速。無論是外鏈指令碼還是內嵌指令碼都是如此。採用無阻塞下載 JavaScript 指令碼的方法:使用<script>標籤的 defer 屬性(僅適用於 IE 和 Firefox 3.5 以上版本);使用動態建立的<script>元素來下載並執行代碼;使用 XHR 對象下載 JavaScript 代碼並注入頁面中。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.