1. 程式人生 > >改善使用者體驗 Web前端優化策略總結.........

改善使用者體驗 Web前端優化策略總結.........

前端是龐大的,包括HTML、CSS、Javascript、Image、Flash等等各種各樣的資源。前端優化是複雜的,針對方方面面的資源都有不同的方式。那麼,前端優化的目的是什麼?

1. 從使用者角度而言,優化能夠讓頁面載入得更快、對使用者的操作響應得更及時,能夠給使用者提供更為友好的體驗。

2. 從服務商角度而言,優化能夠減少頁面請求數、或者減小請求所佔頻寬,能夠節省可觀的資源。

總之,恰當的優化不僅能夠改善站點的使用者體驗並且能夠節省相當的資源利用。前端優化的途徑有很多,按粒度大致可以分為兩類,第一類是頁面級別的優 化,例如HTTP請求數、指令碼的無阻塞載入、內聯指令碼的位置優化等;第二類則是程式碼級別的優化,例如Javascript中的DOM操作優化、CSS選擇 符優化、圖片優化以及HTML結構優化等等。另外,本著提高投入產出比的目的,後文提到的各種優化策略大致按照投入產出比從大到小的順序排列。

一、頁面級優化

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來做請求驗證。儘可能的讓資源能夠 在快取中待得更久。

(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標籤來非同步的請求資料。類似:

 1 <script type="text/javascript">
 2    //Javascript:  
 3    /*Callback函式*/
 4    function myCallback(info) {
 5        //do something here  
 6    } 
 7 </script>    
 8 
 9 <!-- HTML:   -->
10 <script type = "text/javascript"
11 src = "http://abc.com/cb" >
12 </script>
13 <!-- cb返回的內容:  -->
14 <!-- myCallback('Hello world!'); -->

像以上這種方式直接在頁面上寫<script>對頁面的效能也是有影響的,即增加了頁面首次載入的負擔,推遲了DOMLoaded和 window.onload事件的觸發時機。如果時效性允許的話,可以考慮在DOMLoaded事件觸發的時候載入,或者使用setTimeout方式來 靈活的控制載入的時機。

7. 減少不必要的HTTP跳轉

對於以目錄形式訪問的HTTP連結,很多人都會忽略連結最後是否帶’/',假如你的伺服器對此是區別對待的話,那麼你也需要注意,這其中很可能隱藏了301跳轉,增加了多餘請求。具體參見下圖,其中第一個連結是以無’/'結尾的方式訪問的,於是伺服器有了一次跳轉。

8. 避免重複的資源請求

這種情況主要是由於疏忽或頁面由多個模組拼接而成,然後每個模組中請求了同樣的資源時,會導致資源的重複請求。出現的機率不大,但是還是要注意排查,不然可能會出現如下局面,來自這裡。