《高性能網站建設進階指南》css
按理來講,JavaScript在瀏覽器中的性能問題是開發人員面對的最重要的可用性問題。但因爲JavaScript天生的阻塞性質,問題變得複雜。大多數瀏覽器在下載或者執行腳本的同時不會下載其餘內容,使用單線程處理JavaScript的解析和UI的更新。當遇到這種狀況時,但願以不阻塞其餘內容下載的方式來加載JavaScript。有些技術能夠作到這點,使頁面加載更快。html
在介紹JavaScript加載優化技術以前,先看看瀏覽器默認的方式。<script> 標籤能夠放在 <head> 或者 <body> 裏面的任意位置。通常來講都將 <script> 和 <link> 標籤一塊兒放在 <head> 中,這樣一來頁面加載的時候會先加載它們,頁面的樣式和行爲看起來正常。跨域
<html> <head> <meta charset="UTF-8"> <title>Demo</title> <link rel="stylesheet" href="css/base.css"> <link rel="stylesheet" href="css/base2.css"> <script src="scripts/file1.js"></script> <script src="scripts/file2.js"></script> <script src="scripts/file3.js"></script> </head> <body> <p>Hello,CrispElte</p> </body> </html>
儘管這端代碼開始來無傷大雅,但實際上存在幾個性能問題:有三個腳本文件,每一個文件在下載和執行時候都會阻塞頁面的加載。只有腳本執行完成以後,纔會繼續加載其餘資源,好比,圖片,CSS文件,iframe等。
咱們能夠將 <script> 標籤放在頁面的底部,即 </body>標籤以前。儘管腳本文件的加載會阻塞頁面,可是頁面在腳本呢加載以前已經加載完成,因此不用擔憂阻塞。
腳本應該順序執行,可是沒有必要順序下載。IE8第一次實現了腳本的並行下載,可是在腳本下載並執行完畢以前依舊阻塞了後面的資源。
最終的目的時讓腳本與其餘資源並行下載,而且但願兼容全部的瀏覽器。瀏覽器
有幾種動態加載外部腳本的技術可使頁面不會被腳本的阻塞行爲所影響。app
經過XMLHttpRequest從服務端獲取腳本,而後經過eval命令執行內容dom
var xhrObj=new XMLHttpRequest(); xhrObj.onreadystatechange=function(){ if(xhrObj.readyState == 4 && xhrObj.status == 200){ eval(xhrObj.responseText); } } xhrObj.open("GET","file1.js",true); xhrObj.send(null);
這個方法的主要缺陷是,動態加載的腳本必須是同域的。async
與XHR Eval相似,一樣是經過 XMLHttpRequest 對象來獲取腳本,不一樣之處在於,這個方法時不是用 eval 而是建立一個 script 的 DOM 元素,而後將 XMLHttpRequest 的響應寫入script標籤中來執行JavaScript。性能
var xhrObj=new XMLHttpRequest(); xhrObj.onreadystatechange=function(){ if(xhrObj.readyState == 4 && xhrObj.status == 200){ var script=document.createElement("script"); document.getElementsByTagName("head")[0].appendChild(script); script.text=xhrObj.responseText; } } xhrObj.open("GET","file1.js",true); xhrObj.send(null);
和 XHR Eval 方法同樣,加載的腳本必須是同域的。優化
在頁面中 iframe 與其餘資源是並行下載的,能夠利用iframe無阻塞加載JavaScript。
因爲 iframe 認爲返回的是 HTML 文檔,因此將src設置成一個 HTML 文件而不是 js 文件。
而咱們要作的就是在 HTML 文檔中將外部腳本轉換成行內腳本。網站
與 XHR Eval 和 XHR 注入這兩種方法相似,這個方法要求 iframe URL 和主頁同域。知足同域要求以後,咱們須要修改 JavaScript 來建立他們之間的關聯,其本質就是得到引用 iframe 的 JavaScript 標示符。
//使用 "iframes" 中訪問主頁上的 iframe window.frames[0].somefunction(); //使用 "getElementById" 訪問主頁上的iframe document.getElementById("myIframe").contentWindow.someFunction();
能夠在iframe中使用parent變量引用父頁面
function changeBg(){ var body=parent.document.body; body.className="red"; }
歸納一下:主頁面中添加一個 iframe 標籤,其 src 指向一個 HTML 文檔,在這個 HTML 文檔中編寫行內 JavaScript 代碼,也能夠引用外部的 JavaScript 文件
建立一個script標籤並設置其src,代碼很簡單。
var script=document.createElement("script"); script.src="demo2.js"; document.getElementsByTagName("head")[0].appendCHild(script);
下載過程當中用這種方式建立腳本不會阻塞其餘的資源,同時這種方法容許跨域。
在最新的標準中,script標籤訂義了defer屬性和async屬性,都是讓腳本並行下載,可是defer下腳本按照順序執行,而async不按順序執行腳本。
最後一種技術是使用 document.write 把 HTML 標籤 script 寫入頁面中。這種技術只在IE中是並行加載腳本的。雖然多個腳本能夠並行下載,但在下載腳本時,瀏覽器仍然阻塞其餘類型的資源。