如何進行網站優化

前端是龐大的,包括 HTML、 CSS、 Javascript、Image 、Flash等等各類各樣的資源。前端優化是複雜的,針對方方面面的資源都有不一樣的方式。那麼,前端優化的目的是什麼 ?
  1. 從用戶角度而言,優化可以讓頁面加載得更快、對用戶的操做響應得更及時,可以給用戶提供更爲友好的體驗。
  2. 從服務商角度而言,優化可以減小頁面請求數、或者減少請求所佔帶寬,可以節省可觀的資源。
  總之,恰當的優化不只可以改善站點的用戶體驗而且可以節省至關的資源利用。
  前端優化的途徑有不少,按粒度大體能夠分爲兩類,第一類是頁面級別的優化,例如 HTTP請求數、腳本的無阻塞加載、內聯腳本的位置優化等 ;第二類則是代碼級別的優化,例如 Javascript中的DOM 操做優化、CSS選擇符優化、圖片優化以及 HTML結構優化等等。另外,本着提升投入產出比的目的,後文提到的各類優化策略大體按照投入產出比從大到小的順序排列。
  1、頁面級優化
  1. 減小 HTTP請求數
  這條策略基本上全部前端人都知道,並且也是最重要最有效的。都說要減小 HTTP請求,那請求多了到底會怎麼樣呢 ?首先,每一個請求都是有成本的,既包含時間成本也包含資源成本。一個完整的請求都須要通過 DNS尋址、與服務器創建鏈接、發送數據、等待服務器響應、接收數據這樣一個 「漫長」 而複雜的過程。時間成本就是用戶須要看到或者 「感覺」 到這個資源是必需要等待這個過程結束的,資源上因爲每一個請求都須要攜帶數據,所以每一個請求都須要佔用帶寬。另外,因爲瀏覽器進行併發請求的請求數是有上限的 (具體參見此處 ),所以請求數多了之後,瀏覽器須要分批進行請求,所以會增長用戶的等待時間,會給用戶形成站點速度慢這樣一個印象,即便可能用戶能看到的第一屏的資源都已經請求完了,可是瀏覽器的進度條會一直存在。
  減小 HTTP請求數的主要途徑包括:
  (1). 從設計實現層面簡化頁面
  若是你的頁面像百度首頁同樣簡單,那麼接下來的規則基本上都用不着了。保持頁面簡潔、減小資源的使用時最直接的。若是不是這樣,你的頁面須要華麗的皮膚,則繼續閱讀下面的內容。
  (2). 合理設置 HTTP緩存
  緩存的力量是強大的,恰當的緩存設置能夠大大的減小 HTTP請求。以有啊首頁爲例,當瀏覽器沒有緩存的時候訪問一共會發出 78個請求,共 600多 K數據 (如圖 1.1),而當第二次訪問即瀏覽器已緩存以後訪問則僅有 10個請求,共 20多 K數據 (如圖 1.2)。 (這裏須要說明的是,若是直接 F5刷新頁面的話效果是不同的,這種狀況下請求數仍是同樣,不過被緩存資源的請求服務器是 304響應,只有 Header沒有Body ,能夠節省帶寬 )
  怎樣纔算合理設置 ?原則很簡單,能緩存越多越好,能緩存越久越好。例如,不多變化的圖片資源能夠直接經過 HTTP Header中的Expires設置一個很長的過時頭 ;變化不頻繁而又可能會變的資源可使用 Last-Modifed來作請求驗證。儘量的讓資源可以在緩存中待得更久。關於 HTTP緩存的具體設置和原理此處就再也不詳述了,有興趣的能夠參考下列文章:
HTTP1.1協議中關於緩存策略的描述
Fiddler HTTP Performance中關於緩存的介紹
  (3). 資源合併與壓縮
  若是能夠的話,儘量的將外部的腳本、樣式進行合併,多個合爲一個。另外, CSS、 Javascript、Image 均可以用相應的工具進行壓縮,壓縮後每每能省下很多空間。
  (4). CSS Sprites
  合併 CSS圖片,減小請求數的又一個好辦法。
  (5). Inline Images
  使用 data: URL scheme的方式將圖片嵌入到頁面或 CSS中,若是不考慮資源管理上的問題的話,不失爲一個好辦法。若是是嵌入頁面的話換來的是增大了頁面的體積,並且沒法利用瀏覽器緩存。使用在 CSS中的圖片則更爲理想一些。
  (6). Lazy Load Images(本身對這一塊的內容仍是不瞭解)
  這條策略實際上並不必定能減小 HTTP請求數,可是卻能在某些條件下或者頁面剛加載時減小 HTTP請求數。對於圖片而言,在頁面剛加載的時候能夠只加載第一屏,當用戶繼續日後滾屏的時候才加載後續的圖片。這樣一來,假如用戶只對第一屏的內容感興趣時,那剩餘的圖片請求就都節省了。 有啊首頁 曾經的作法是在加載的時候把第一屏以後的圖片地址緩存在 Textarea標籤中,待用戶往下滾屏的時候才 「惰性」 加載。javascript

  2. 將外部腳本置底(將腳本內容在頁面信息內容加載後再加載)
  前文有談到,瀏覽器是能夠併發請求的,這一特色使得其可以更快的加載資源,然而外鏈腳本在加載時卻會阻塞其餘資源,例如在腳本加載完成以前,它後面的圖片、樣式以及其餘腳本都處於阻塞狀態,直到腳本加載完成後纔會開始加載。若是將腳本放在比較靠前的位置,則會影響整個頁面的加載速度從而影響用戶體驗。解決這一問題的方法有不少,在 這裏有比較詳細的介紹 (這裏是譯文和 更詳細的例子 ),而最簡單可依賴的方法就是將腳本儘量的日後挪,減小對併發下載的影響。
  3. 異步執行 inline腳本(其實原理和上面是同樣,保證腳本在頁面內容後面加載。)
  inline腳本對性能的影響與外部腳本相比,是有過之而無不及。首頁,與外部腳本同樣, inline腳本在執行的時候同樣會阻塞併發請求,除此以外,因爲瀏覽器在頁面處理方面是單線程的,當 inline腳本在頁面渲染以前執行時,頁面的渲染工做則會被推遲。簡而言之, inline腳本在執行的時候,頁面處於空白狀態。鑑於以上兩點緣由,建議將執行時間較長的 inline腳本異步執行,異步的方式有不少種,例如使用 script元素的defer 屬性(存在兼容性問題和其餘一些問題,例如不能使用 document.write)、使用setTimeout ,此外,在HTML5中引入了 Web Workers的機制,偏偏能夠解決此類問題。css

  4. Lazy Load Javascript(只有在須要加載的時候加載,在通常狀況下並不加載信息內容。)
  隨着 Javascript框架的流行,愈來愈多的站點也使用起了框架。不過,一個框架每每包括了不少的功能實現,這些功能並非每個頁面都須要的,若是下載了不須要的腳本則算得上是一種資源浪費 -既浪費了帶寬又浪費了執行花費的時間。目前的作法大概有兩種,一種是爲那些流量特別大的頁面專門定製一個專用的 mini版框架,另外一種則是 Lazy Load。YUI 則使用了第二種方式,在 YUI的實現中,最初只加載核心模塊,其餘模塊能夠等到須要使用的時候才加載。html

  5. 將 CSS放在 HEAD中
  若是將 CSS放在其餘地方好比 BODY中,則瀏覽器有可能還未下載和解析到 CSS就已經開始渲染頁面了,這就致使頁面由無 CSS狀態跳轉到 CSS狀態,用戶體驗比較糟糕。除此以外,有些瀏覽器會在 CSS下載完成後纔開始渲染頁面,若是 CSS放在靠下的位置則會致使瀏覽器將渲染時間推遲。
  6. 異步請求 Callback(就是將一些行爲樣式提取出來,慢慢的加載信息的內容)
  在某些頁面中可能存在這樣一種需求,須要使用 script標籤來異步的請求數據。相似:
  Javascript:
/*Callback 函數*/ 
function myCallback(info){ 
//do something here 

  HTML:前端

  cb返回的內容 :
myCallback('Hello world!');
像以上這種方式直接在頁面上寫 <script>對頁面的性能也是有影響的,即增長了頁面首次加載的負擔,推遲了 DOMLoaded和window.onload 事件的觸發時機。若是時效性容許的話,能夠考慮在 DOMLoaded事件觸發的時候加載,或者使用 setTimeout方式來靈活的控制加載的時機。
  7. 減小沒必要要的 HTTP跳轉
  對於以目錄形式訪問的 HTTP連接,不少人都會忽略連接最後是否帶 ’/',假如你的服務器對此是區別對待的話,那麼你也須要注意,這其中極可能隱藏了 301跳轉,增長了多餘請求。具體參見下圖,其中第一個連接是以無 ’/'結尾的方式訪問的,因而服務器有了一次跳轉。
  8. 避免重複的資源請求
  這種狀況主要是因爲疏忽或頁面由多個模塊拼接而成,而後每一個模塊中請求了一樣的資源時,會致使資源的重複請求java

  2、代碼級優化
  1. Javascript
  (1). DOM
  DOM操做應該是腳本中最耗性能的一類操做,例如增長、修改、刪除 DOM元素或者對 DOM集合進行操做。若是腳本中包含了大量的 DOM操做則須要注意如下幾點:
  a. HTML Collection(HTML收集器,返回的是一個數組內容信息)
  在腳本中 document.images、document.forms 、getElementsByTagName()返回的都是 HTMLCollection類型的集合,在平時使用的時候大多將它做爲數組來使用,由於它有 length屬性,也可使用索引訪問每個元素。不過在訪問性能上則比數組要差不少,緣由是這個集合並非一個靜態的結果,它表示的僅僅是一個特定的查詢,每次訪問該集合時都會從新執行這個查詢從而更新查詢結果。所謂的 「訪問集合」 包括讀取集合的 length屬性、訪問集合中的元素。
  所以,當你須要遍歷 HTML Collection的時候,儘可能將它轉爲數組後再訪問,以提升性能。即便不轉換爲數組,也請儘量少的訪問它,例如在遍歷的時候能夠將 length屬性、成員保存到局部變量後再使用局部變量。
  b. Reflow & Repaint
  除了上面一點以外, DOM操做還須要考慮瀏覽器的 Reflow和Repaint ,由於這些都是須要消耗資源的,具體的能夠參加如下文章:
如何減小瀏覽器的repaint和reflow?
Understanding Internet Explorer Rendering Behaviour
Notes on HTML Reflowweb

  (2). 慎用 with
with(obj){ p = 1}; 代碼塊的行爲其實是修改了代碼塊中的 執行環境 ,將obj放在了其做用域鏈的最前端,在 with代碼塊中訪問非局部變量是都是先從 obj上開始查找,若是沒有再依次按做用域鏈向上查找,所以使用 with至關於增長了做用域鏈長度。而每次查找做用域鏈都是要消耗時間的,過長的做用域鏈會致使查找性能降低。
  所以,除非你能確定在 with代碼中只訪問 obj中的屬性,不然慎用 with,替代的可使用局部變量緩存須要訪問的屬性。
  (3). 避免使用 eval和 Function
  每次 eval 或 Function 構造函數做用於字符串表示的源代碼時,腳本引擎都須要將源代碼轉換成可執行代碼。這是很消耗資源的操做 —— 一般比簡單的函數調用慢 100倍以上。
  eval 函數效率特別低,因爲事先沒法知曉傳給 eval 的字符串中的內容,eval在其上下文中解釋要處理的代碼,也就是說編譯器沒法優化上下文,所以只能有瀏覽器在運行時解釋代碼。這對性能影響很大。
  Function 構造函數比 eval略好,由於使用此代碼不會影響周圍代碼 ;但其速度仍很慢。
  此外,使用 eval和 Function也不利於Javascript 壓縮工具執行壓縮。
  (4). 減小做用域鏈查找(這方面設計到一些內容的相關問題)
  前文談到了做用域鏈查找問題,這一點在循環中是尤爲須要注意的問題。若是在循環中須要訪問非本做用域下的變量時請在遍歷以前用局部變量緩存該變量,並在遍歷結束後再重寫那個變量,這一點對全局變量尤爲重要,由於全局變量處於做用域鏈的最頂端,訪問時的查找次數是最多的。
  低效率的寫法:
// 全局變量 
var globalVar = 1; 
function myCallback(info){ 
for( var i = 100000; i--;){ 
//每次訪問 globalVar 都須要查找到做用域鏈最頂端,本例中須要訪問 100000 次 
globalVar += i; 
}

  更高效的寫法:
// 全局變量 
var globalVar = 1; 
function myCallback(info){ 
//局部變量緩存全局變量 
var localVar = globalVar; 
for( var i = 100000; i--;){ 
//訪問局部變量是最快的 
localVar += i; 

//本例中只須要訪問 2次全局變量
在函數中只須要將 globalVar中內容的值賦給localVar 中區
globalVar = localVar; 
}
  此外,要減小做用域鏈查找還應該減小閉包的使用。
  (5). 數據訪問
  Javascript中的數據訪問包括直接量 (字符串、正則表達式 )、變量、對象屬性以及數組,其中對直接量和局部變量的訪問是最快的,對對象屬性以及數組的訪問須要更大的開銷。當出現如下狀況時,建議將數據放入局部變量:
  a. 對任何對象屬性的訪問超過 1次
  b. 對任何數組成員的訪問次數超過 1次
  另外,還應當儘量的減小對對象以及數組深度查找。
  (6). 字符串拼接
  在 Javascript中使用"+" 號來拼接字符串效率是比較低的,由於每次運行都會開闢新的內存並生成新的字符串變量,而後將拼接結果賦值給新變量。與之相比更爲高效的作法是使用數組的 join方法,即將須要拼接的字符串放在數組中最後調用其 join方法獲得結果。不過因爲使用數組也有必定的開銷,所以當須要拼接的字符串較多的時候能夠考慮用此方法。正則表達式

  關於 Javascript優化的更詳細介紹請參考:
Write Efficient Javascript(PPT)
Efficient JavaScript
  2. CSS選擇符
  在大多數人的觀念中,都以爲瀏覽器對 CSS選擇符的解析式從左往右進行的,例如
#toc A { color: #444; }
  這樣一個選擇符,若是是從右往左解析則效率會很高,由於第一個 ID選擇基本上就把查找的範圍限定了,但實際上瀏覽器對選擇符的解析是從右往左進行的。如上面的選擇符,瀏覽器必須遍歷查找每個 A標籤的祖先節點,效率並不像以前想象的那樣高。根據瀏覽器的這一行爲特色,在寫選擇符的時候須要注意不少事項,有人已經一一列舉了, 詳情參考此處數組

  3. HTML
  對 HTML自己的優化現現在也愈來愈多的受人關注了,詳情能夠參見這篇 總結性文章 。瀏覽器

  4. Image壓縮
  圖片壓縮是個技術活,不過現現在這方面的工具也很是多,壓縮以後每每能帶來不錯的效果,具體的壓縮原理以及方法在《 Even Faster Web Sites》第10 章有很詳細的介紹,有興趣的能夠去看看。
  總結
  本文從頁面級以及代碼級兩個粒度對前端優化的各類方式作了一個總結,這些方法基本上都是前端開發人員在開發的過程當中能夠借鑑和實踐的,除此以外,完整的前端優化還應該包括不少其餘的途徑,例如 CDN、 Gzip、多域名、無 Cookie服務器等等,因爲對於開發人員的可操做性並不強大,在此也就很少敘述了,詳細的能夠參考 Yahoo和Google 的這些「金科玉律 緩存

  • content方面

    • 減小HTTP請求:合併文件、CSS精靈、inline Image
    • 減小DNS查詢:DNS緩存、將資源分佈到恰當數量的主機名
    • 減小DOM元素數量
  • Server方面

    • 使用CDN
    • 配置ETag
    • 對組件使用Gzip壓縮
  • Cookie方面

    • 減少cookie大小
  • css方面

    • 將樣式表放到頁面頂部
    • 不使用CSS表達式
    • 使用<link>不使用@import
  • Javascript方面

    • 將腳本放到頁面底部
    • javascriptcss從外部引入
    • 壓縮javascriptcss
    • 刪除不須要的腳本
    • 減小DOM訪問
  • 圖片方面

    • 優化圖片:根據實際顏色須要選擇色深、壓縮
    • 優化css精靈
    • 不要在HTML中拉伸圖片

前端是龐大的,包括 HTML、 CSS、 Javascript、Image 、Flash等等各類各樣的資源。前端優化是複雜的,針對方方面面的資源都有不一樣的方式。那麼,前端優化的目的是什麼 ?
  1. 從用戶角度而言,優化可以讓頁面加載得更快、對用戶的操做響應得更及時,可以給用戶提供更爲友好的體驗。
  2. 從服務商角度而言,優化可以減小頁面請求數、或者減少請求所佔帶寬,可以節省可觀的資源。
  總之,恰當的優化不只可以改善站點的用戶體驗而且可以節省至關的資源利用。
  前端優化的途徑有不少,按粒度大體能夠分爲兩類,第一類是頁面級別的優化,例如 HTTP請求數、腳本的無阻塞加載、內聯腳本的位置優化等 ;第二類則是代碼級別的優化,例如 Javascript中的DOM 操做優化、CSS選擇符優化、圖片優化以及 HTML結構優化等等。另外,本着提升投入產出比的目的,後文提到的各類優化策略大體按照投入產出比從大到小的順序排列。
  1、頁面級優化
  1. 減小 HTTP請求數
  這條策略基本上全部前端人都知道,並且也是最重要最有效的。都說要減小 HTTP請求,那請求多了到底會怎麼樣呢 ?首先,每一個請求都是有成本的,既包含時間成本也包含資源成本。一個完整的請求都須要通過 DNS尋址、與服務器創建鏈接、發送數據、等待服務器響應、接收數據這樣一個 「漫長」 而複雜的過程。時間成本就是用戶須要看到或者 「感覺」 到這個資源是必需要等待這個過程結束的,資源上因爲每一個請求都須要攜帶數據,所以每一個請求都須要佔用帶寬。另外,因爲瀏覽器進行併發請求的請求數是有上限的 (具體參見此處 ),所以請求數多了之後,瀏覽器須要分批進行請求,所以會增長用戶的等待時間,會給用戶形成站點速度慢這樣一個印象,即便可能用戶能看到的第一屏的資源都已經請求完了,可是瀏覽器的進度條會一直存在。
  減小 HTTP請求數的主要途徑包括:
  (1). 從設計實現層面簡化頁面
  若是你的頁面像百度首頁同樣簡單,那麼接下來的規則基本上都用不着了。保持頁面簡潔、減小資源的使用時最直接的。若是不是這樣,你的頁面須要華麗的皮膚,則繼續閱讀下面的內容。
  (2). 合理設置 HTTP緩存
  緩存的力量是強大的,恰當的緩存設置能夠大大的減小 HTTP請求。以有啊首頁爲例,當瀏覽器沒有緩存的時候訪問一共會發出 78個請求,共 600多 K數據 (如圖 1.1),而當第二次訪問即瀏覽器已緩存以後訪問則僅有 10個請求,共 20多 K數據 (如圖 1.2)。 (這裏須要說明的是,若是直接 F5刷新頁面的話效果是不同的,這種狀況下請求數仍是同樣,不過被緩存資源的請求服務器是 304響應,只有 Header沒有Body ,能夠節省帶寬 )
  怎樣纔算合理設置 ?原則很簡單,能緩存越多越好,能緩存越久越好。例如,不多變化的圖片資源能夠直接經過 HTTP Header中的Expires設置一個很長的過時頭 ;變化不頻繁而又可能會變的資源可使用 Last-Modifed來作請求驗證。儘量的讓資源可以在緩存中待得更久。關於 HTTP緩存的具體設置和原理此處就再也不詳述了,有興趣的能夠參考下列文章:
HTTP1.1協議中關於緩存策略的描述
Fiddler HTTP Performance中關於緩存的介紹
  (3). 資源合併與壓縮
  若是能夠的話,儘量的將外部的腳本、樣式進行合併,多個合爲一個。另外, CSS、 Javascript、Image 均可以用相應的工具進行壓縮,壓縮後每每能省下很多空間。
  (4). CSS Sprites
  合併 CSS圖片,減小請求數的又一個好辦法。
  (5). Inline Images
  使用 data: URL scheme的方式將圖片嵌入到頁面或 CSS中,若是不考慮資源管理上的問題的話,不失爲一個好辦法。若是是嵌入頁面的話換來的是增大了頁面的體積,並且沒法利用瀏覽器緩存。使用在 CSS中的圖片則更爲理想一些。
  (6). Lazy Load Images(本身對這一塊的內容仍是不瞭解)
  這條策略實際上並不必定能減小 HTTP請求數,可是卻能在某些條件下或者頁面剛加載時減小 HTTP請求數。對於圖片而言,在頁面剛加載的時候能夠只加載第一屏,當用戶繼續日後滾屏的時候才加載後續的圖片。這樣一來,假如用戶只對第一屏的內容感興趣時,那剩餘的圖片請求就都節省了。 有啊首頁 曾經的作法是在加載的時候把第一屏以後的圖片地址緩存在 Textarea標籤中,待用戶往下滾屏的時候才 「惰性」 加載。

  2. 將外部腳本置底(將腳本內容在頁面信息內容加載後再加載)
  前文有談到,瀏覽器是能夠併發請求的,這一特色使得其可以更快的加載資源,然而外鏈腳本在加載時卻會阻塞其餘資源,例如在腳本加載完成以前,它後面的圖片、樣式以及其餘腳本都處於阻塞狀態,直到腳本加載完成後纔會開始加載。若是將腳本放在比較靠前的位置,則會影響整個頁面的加載速度從而影響用戶體驗。解決這一問題的方法有不少,在 這裏有比較詳細的介紹 (這裏是譯文和 更詳細的例子 ),而最簡單可依賴的方法就是將腳本儘量的日後挪,減小對併發下載的影響。
  3. 異步執行 inline腳本(其實原理和上面是同樣,保證腳本在頁面內容後面加載。)
  inline腳本對性能的影響與外部腳本相比,是有過之而無不及。首頁,與外部腳本同樣, inline腳本在執行的時候同樣會阻塞併發請求,除此以外,因爲瀏覽器在頁面處理方面是單線程的,當 inline腳本在頁面渲染以前執行時,頁面的渲染工做則會被推遲。簡而言之, inline腳本在執行的時候,頁面處於空白狀態。鑑於以上兩點緣由,建議將執行時間較長的 inline腳本異步執行,異步的方式有不少種,例如使用 script元素的defer 屬性(存在兼容性問題和其餘一些問題,例如不能使用 document.write)、使用setTimeout ,此外,在HTML5中引入了 Web Workers的機制,偏偏能夠解決此類問題。

  4. Lazy Load Javascript(只有在須要加載的時候加載,在通常狀況下並不加載信息內容。)
  隨着 Javascript框架的流行,愈來愈多的站點也使用起了框架。不過,一個框架每每包括了不少的功能實現,這些功能並非每個頁面都須要的,若是下載了不須要的腳本則算得上是一種資源浪費 -既浪費了帶寬又浪費了執行花費的時間。目前的作法大概有兩種,一種是爲那些流量特別大的頁面專門定製一個專用的 mini版框架,另外一種則是 Lazy Load。YUI 則使用了第二種方式,在 YUI的實現中,最初只加載核心模塊,其餘模塊能夠等到須要使用的時候才加載。

  5. 將 CSS放在 HEAD中
  若是將 CSS放在其餘地方好比 BODY中,則瀏覽器有可能還未下載和解析到 CSS就已經開始渲染頁面了,這就致使頁面由無 CSS狀態跳轉到 CSS狀態,用戶體驗比較糟糕。除此以外,有些瀏覽器會在 CSS下載完成後纔開始渲染頁面,若是 CSS放在靠下的位置則會致使瀏覽器將渲染時間推遲。
  6. 異步請求 Callback(就是將一些行爲樣式提取出來,慢慢的加載信息的內容)
  在某些頁面中可能存在這樣一種需求,須要使用 script標籤來異步的請求數據。相似:
  Javascript:
/*Callback 函數*/ 
function myCallback(info){ 
//do something here 

  HTML:

  cb返回的內容 :
myCallback('Hello world!');
像以上這種方式直接在頁面上寫 <script>對頁面的性能也是有影響的,即增長了頁面首次加載的負擔,推遲了 DOMLoaded和window.onload 事件的觸發時機。若是時效性容許的話,能夠考慮在 DOMLoaded事件觸發的時候加載,或者使用 setTimeout方式來靈活的控制加載的時機。
  7. 減小沒必要要的 HTTP跳轉
  對於以目錄形式訪問的 HTTP連接,不少人都會忽略連接最後是否帶 ’/',假如你的服務器對此是區別對待的話,那麼你也須要注意,這其中極可能隱藏了 301跳轉,增長了多餘請求。具體參見下圖,其中第一個連接是以無 ’/'結尾的方式訪問的,因而服務器有了一次跳轉。
  8. 避免重複的資源請求
  這種狀況主要是因爲疏忽或頁面由多個模塊拼接而成,而後每一個模塊中請求了一樣的資源時,會致使資源的重複請求

  2、代碼級優化
  1. Javascript
  (1). DOM
  DOM操做應該是腳本中最耗性能的一類操做,例如增長、修改、刪除 DOM元素或者對 DOM集合進行操做。若是腳本中包含了大量的 DOM操做則須要注意如下幾點:
  a. HTML Collection(HTML收集器,返回的是一個數組內容信息)
  在腳本中 document.images、document.forms 、getElementsByTagName()返回的都是 HTMLCollection類型的集合,在平時使用的時候大多將它做爲數組來使用,由於它有 length屬性,也可使用索引訪問每個元素。不過在訪問性能上則比數組要差不少,緣由是這個集合並非一個靜態的結果,它表示的僅僅是一個特定的查詢,每次訪問該集合時都會從新執行這個查詢從而更新查詢結果。所謂的 「訪問集合」 包括讀取集合的 length屬性、訪問集合中的元素。
  所以,當你須要遍歷 HTML Collection的時候,儘可能將它轉爲數組後再訪問,以提升性能。即便不轉換爲數組,也請儘量少的訪問它,例如在遍歷的時候能夠將 length屬性、成員保存到局部變量後再使用局部變量。
  b. Reflow & Repaint
  除了上面一點以外, DOM操做還須要考慮瀏覽器的 Reflow和Repaint ,由於這些都是須要消耗資源的,具體的能夠參加如下文章:
如何減小瀏覽器的repaint和reflow?
Understanding Internet Explorer Rendering Behaviour
Notes on HTML Reflow

  (2). 慎用 with
with(obj){ p = 1}; 代碼塊的行爲其實是修改了代碼塊中的 執行環境 ,將obj放在了其做用域鏈的最前端,在 with代碼塊中訪問非局部變量是都是先從 obj上開始查找,若是沒有再依次按做用域鏈向上查找,所以使用 with至關於增長了做用域鏈長度。而每次查找做用域鏈都是要消耗時間的,過長的做用域鏈會致使查找性能降低。
  所以,除非你能確定在 with代碼中只訪問 obj中的屬性,不然慎用 with,替代的可使用局部變量緩存須要訪問的屬性。
  (3). 避免使用 eval和 Function
  每次 eval 或 Function 構造函數做用於字符串表示的源代碼時,腳本引擎都須要將源代碼轉換成可執行代碼。這是很消耗資源的操做 —— 一般比簡單的函數調用慢 100倍以上。
  eval 函數效率特別低,因爲事先沒法知曉傳給 eval 的字符串中的內容,eval在其上下文中解釋要處理的代碼,也就是說編譯器沒法優化上下文,所以只能有瀏覽器在運行時解釋代碼。這對性能影響很大。
  Function 構造函數比 eval略好,由於使用此代碼不會影響周圍代碼 ;但其速度仍很慢。
  此外,使用 eval和 Function也不利於Javascript 壓縮工具執行壓縮。
  (4). 減小做用域鏈查找(這方面設計到一些內容的相關問題)
  前文談到了做用域鏈查找問題,這一點在循環中是尤爲須要注意的問題。若是在循環中須要訪問非本做用域下的變量時請在遍歷以前用局部變量緩存該變量,並在遍歷結束後再重寫那個變量,這一點對全局變量尤爲重要,由於全局變量處於做用域鏈的最頂端,訪問時的查找次數是最多的。
  低效率的寫法:
// 全局變量 
var globalVar = 1; 
function myCallback(info){ 
for( var i = 100000; i--;){ 
//每次訪問 globalVar 都須要查找到做用域鏈最頂端,本例中須要訪問 100000 次 
globalVar += i; 
}

  更高效的寫法:
// 全局變量 
var globalVar = 1; 
function myCallback(info){ 
//局部變量緩存全局變量 
var localVar = globalVar; 
for( var i = 100000; i--;){ 
//訪問局部變量是最快的 
localVar += i; 

//本例中只須要訪問 2次全局變量
在函數中只須要將 globalVar中內容的值賦給localVar 中區
globalVar = localVar; 
}
  此外,要減小做用域鏈查找還應該減小閉包的使用。
  (5). 數據訪問
  Javascript中的數據訪問包括直接量 (字符串、正則表達式 )、變量、對象屬性以及數組,其中對直接量和局部變量的訪問是最快的,對對象屬性以及數組的訪問須要更大的開銷。當出現如下狀況時,建議將數據放入局部變量:
  a. 對任何對象屬性的訪問超過 1次
  b. 對任何數組成員的訪問次數超過 1次
  另外,還應當儘量的減小對對象以及數組深度查找。
  (6). 字符串拼接
  在 Javascript中使用"+" 號來拼接字符串效率是比較低的,由於每次運行都會開闢新的內存並生成新的字符串變量,而後將拼接結果賦值給新變量。與之相比更爲高效的作法是使用數組的 join方法,即將須要拼接的字符串放在數組中最後調用其 join方法獲得結果。不過因爲使用數組也有必定的開銷,所以當須要拼接的字符串較多的時候能夠考慮用此方法。

  關於 Javascript優化的更詳細介紹請參考:
Write Efficient Javascript(PPT)
Efficient JavaScript
  2. CSS選擇符
  在大多數人的觀念中,都以爲瀏覽器對 CSS選擇符的解析式從左往右進行的,例如
#toc A { color: #444; }
  這樣一個選擇符,若是是從右往左解析則效率會很高,由於第一個 ID選擇基本上就把查找的範圍限定了,但實際上瀏覽器對選擇符的解析是從右往左進行的。如上面的選擇符,瀏覽器必須遍歷查找每個 A標籤的祖先節點,效率並不像以前想象的那樣高。根據瀏覽器的這一行爲特色,在寫選擇符的時候須要注意不少事項,有人已經一一列舉了, 詳情參考此處

  3. HTML
  對 HTML自己的優化現現在也愈來愈多的受人關注了,詳情能夠參見這篇 總結性文章 。

  4. Image壓縮
  圖片壓縮是個技術活,不過現現在這方面的工具也很是多,壓縮以後每每能帶來不錯的效果,具體的壓縮原理以及方法在《 Even Faster Web Sites》第10 章有很詳細的介紹,有興趣的能夠去看看。
  總結
  本文從頁面級以及代碼級兩個粒度對前端優化的各類方式作了一個總結,這些方法基本上都是前端開發人員在開發的過程當中能夠借鑑和實踐的,除此以外,完整的前端優化還應該包括不少其餘的途徑,例如 CDN、 Gzip、多域名、無 Cookie服務器等等,因爲對於開發人員的可操做性並不強大,在此也就很少敘述了,詳細的能夠參考 Yahoo和Google 的這些「金科玉律 

相關文章
相關標籤/搜索