前端優化策略

轉自:http://www.2cto.com/kf/201604/498725.htmljavascript

         網站的劃分通常爲二:前端和後臺。咱們能夠理解成後臺是用來實現網站的功能的,好比:實現用戶註冊,用戶可以爲文章發表評論等等。而前端呢?其實應該是屬於功能的表現。而且影響用戶訪問體驗的絕大部分來自前端頁面。html

        而咱們建設網站的目的是什麼呢?不就是爲了讓目標人羣來訪問嗎?因此咱們能夠理解成前端纔是真正和用戶接觸的。除了後臺須要在性能上作優化外,其實前端的頁面更須要在性能優化上下功夫,只有這樣才能給咱們的用戶帶來更好的用戶體驗。就好像,好多人問,男人在找女友的時候是否是隻看外表,一些智慧的男人給出了這樣的回答:臉蛋和身材決定了我是否想去了解她的思想,思想決定了我是否會一票否決她的臉蛋和身材。同理,網站也是這樣,網站前端的用戶體驗決定了用戶是否想要去使用網站的功能,而網站的功能決定了用戶是否會一票否決前端體驗前端

        不只僅如此,若是前端優化得好,他不只能夠爲企業節約成本,他還能給用戶帶來更多的用戶,由於加強的用戶體驗。說了這麼多,那麼咱們應該如何對咱們前端的頁面進行性能優化呢?java

        通常說來,web前端指網站業務邏輯以前的部分,包括瀏覽器加載、網站視圖模型、圖片服務、CDN服務等,主要優化手段有瀏覽器訪問、使用反向代理才、CDN等。web

瀏覽器訪問優化正則表達式

瀏覽器請求處理流程以下圖:數組

 

一、減小http請求,合理設置 HTTP緩存瀏覽器

        http協議是無狀態的應用層協議,意味着每次http請求都須要創建通訊鏈路、進行數據傳輸,而在服務器端,每一個http都須要啓動獨立的線程去處理。這些通訊和服務的開銷都很昂貴,減小http請求的數目可有效提升訪問性能。緩存

        減小http的主要手段是合併CSS、合併JavaScript、合併圖片。將瀏覽器一次訪問須要的javascript和CSS合併成一個文件,這樣瀏覽器就只須要一次請求。圖片也能夠合併,多張圖片合併成一張,若是每張圖片都有不一樣的超連接,可經過CSS偏移響應鼠標點擊操做,構造不一樣的URL。
         緩存的力量是強大的,恰當的緩存設置能夠大大的減小 HTTP請求。假設某網站首頁,當瀏覽器沒有緩存的時候訪問一共會發出 78個請求,共 600多 K數據,而當第二次訪問即瀏覽器已緩存以後訪問則僅有 10個請求,共 20多 K數據。 (這裏須要說明的是,若是直接 F5刷新頁面的話效果是不同的,這種狀況下請求數仍是同樣,不過被緩存資源的請求服務器是 304響應,只有 Header沒有Body,能夠節省帶寬 )性能優化

        怎樣纔算合理設置 ?原則很簡單,能緩存越多越好,能緩存越久越好。例如,不多變化的圖片資源能夠直接經過 HTTP Header中的Expires設置一個很長的過時頭 ;變化不頻繁而又可能會變的資源可使用 Last-Modifed來作請求驗證。儘量的讓資源可以在緩存中待得更久。關於 HTTP緩存的具體設置和原理此處就再也不詳述了。

二、使用瀏覽器緩存

        對一個網站而言,CSS、javascript、logo、圖標這些靜態資源文件更新的頻率都比較低,而這些文件又幾乎是每次http請求都須要的,若是將這些文件緩存在瀏覽器中,能夠極好的改善性能。經過設置http頭中的cache-control和expires的屬性,可設定瀏覽器緩存,緩存時間能夠是數天,甚至是幾個月。

        在某些時候,靜態資源文件變化須要及時應用到客戶端瀏覽器,這種狀況,可經過改變文件名實現,即更新javascript文件並非更新javascript文件內容,而是生成一個新的js文件並更新HTML文件中的引用。
        使用瀏覽器緩存策略的網站在更新靜態資源時,應採用逐量更新的方法,好比須要更新10個圖標文件,不宜把10個文件一次所有更新,而是應該一個文件一個文件逐步更新,並有必定的間隔時間,以避免用戶瀏覽器突然大量緩存失效,集中更新緩存,形成服務器負載驟增、網絡堵塞的狀況。

三、啓用壓縮

        在服務器端對文件進行壓縮,在瀏覽器端對文件解壓縮,可有效減小通訊傳輸的數據量。若是能夠的話,儘量的將外部的腳本、樣式進行合併,多個合爲一個。文本文件的壓縮效率可達到80%以上,所以HTML、CSS、javascript文件啓用GZip壓縮可達到較好的效果。可是壓縮對服務器和瀏覽器產生必定的壓力,在通訊帶寬良好,而服務器資源不足的狀況下要權衡考慮。

四、CSS Sprites

合併 CSS圖片,減小請求數的又一個好辦法。

五、LazyLoad Images

        這條策略實際上並不必定能減小 HTTP請求數,可是卻能在某些條件下或者頁面剛加載時減小 HTTP請求數。對於圖片而言,在頁面剛加載的時候能夠只加載第一屏,當用戶繼續日後滾屏的時候才加載後續的圖片。這樣一來,假如用戶只對第一屏的內容感興趣時,那剩餘的圖片請求就都節省了。

六、CSS放在頁面最上部,javascript放在頁面最下面

       瀏覽器會在下載完成所有CSS以後纔對整個頁面進行渲染,所以最好的作法是將CSS放在頁面最上面,讓瀏覽器儘快下載CSS。若是將 CSS放在其餘地方好比 BODY中,則瀏覽器有可能還未下載和解析到 CSS就已經開始渲染頁面了,這就致使頁面由無 CSS狀態跳轉到 CSS狀態,用戶體驗比較糟糕,因此能夠考慮將CSS放在HEAD中。

        Javascript則相反,瀏覽器在加載javascript後當即執行,有可能會阻塞整個頁面,形成頁面顯示緩慢,所以javascript最好放在頁面最下面。但若是頁面解析時就須要用到javascript,這時放到底部就不合適了。

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

七、異步請求Callback(就是將一些行爲樣式提取出來,慢慢的加載信息的內容)

在某些頁面中可能存在這樣一種需求,須要使用 script標籤來異步的請求數據。相似:

[javascript]  view plain  copy
 
 print?
  1. <span style="font-size:14px;">/*Callback 函數*/  
  2.     function myCallback(info){   
  3.         //do something here   
  4.     }   
  5.  HTML:  
  6.   Callback返回的內容 :  
  7.    myCallback('Hello world!');  
  8. </span>  

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

八、減小cookie傳輸

        一方面,cookie包含在每次請求和響應中,太大的cookie會嚴重影響數據傳輸,所以哪些數據須要寫入cookie須要慎重考慮,儘可能減小cookie中傳輸的數據量。另外一方面,對於某些靜態資源的訪問,如CSS、script等,發送cookie沒有意義,能夠考慮靜態資源使用獨立域名訪問,避免請求靜態資源時發送cookie,減小cookie傳輸次數。

九、Javascript代碼優化

(1). DOM  

a.HTML Collection(HTML收集器,返回的是一個數組內容信息) 
  在腳本中 document.images、document.forms、getElementsByTagName()返回的都是HTMLCollection類型的集合,在平時使用的時候大多將它做爲數組來使用,由於它有 length屬性,也可使用索引訪問每個元素。不過在訪問性能上則比數組要差不少,緣由是這個集合並非一個靜態的結果,它表示的僅僅是一個特定的查詢,每次訪問該集合時都會從新執行這個查詢從而更新查詢結果。所謂的「訪問集合」 包括讀取集合的 length屬性、訪問集合中的元素。 
  所以,當你須要遍歷 HTML Collection的時候,儘可能將它轉爲數組後再訪問,以提升性能。即便不轉換爲數組,也請儘量少的訪問它,例如在遍歷的時候能夠將 length屬性、成員保存到局部變量後再使用局部變量。   
b. Reflow & Repaint   
  除了上面一點以外, DOM操做還須要考慮瀏覽器的Reflow和Repaint ,由於這些都是須要消耗資源的。

(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). 減小做用域鏈查找

前文談到了做用域鏈查找問題,這一點在循環中是尤爲須要注意的問題。若是在循環中須要訪問非本做用域下的變量時請在遍歷以前用局部變量緩存該變量,並在遍歷結束後再重寫那個變量,這一點對全局變量尤爲重要,由於全局變量處於做用域鏈的最頂端,訪問時的查找次數是最多的。 
低效率的寫法:

[javascript]  view plain  copy
 
 print?
  1. <span style="font-size:14px;">// 全局變量   
  2. var globalVar = 1;   
  3. function myCallback(info){   
  4.     for( var i = 100000; i--;){   
  5.         //每次訪問 globalVar 都須要查找到做用域鏈最頂端,本例中須要訪問 100000 次   
  6.         globalVar += i;   
  7.     }  
  8. }   
  9. </span>  

 

更高效的寫法:

[javascript]  view plain  copy
 
 print?
  1. <span style="font-size:14px;">// 全局變量   
  2. var globalVar = 1;   
  3. function myCallback(info){   
  4.     //局部變量緩存全局變量   
  5.     var localVar = globalVar;   
  6.     for( var i = 100000; i--;){   
  7.     //訪問局部變量是最快的   
  8.     localVar += i;   
  9.     }   
  10.     //本例中只須要訪問 2次全局變量  
  11.     在函數中只須要將 globalVar中內容的值賦給localVar 中  
  12.     globalVar = localVar;   
  13. }  
  14. </span>  

 

此外,要減小做用域鏈查找還應該減小閉包的使用。

(5). 數據訪問

  Javascript中的數據訪問包括直接量 (字符串、正則表達式 )、變量、對象屬性以及數組,其中對直接量和局部變量的訪問是最快的,對對象屬性以及數組的訪問須要更大的開銷。當出現如下狀況時,建議將數據放入局部變量: 
  a. 對任何對象屬性的訪問超過 1次 
  b. 對任何數組成員的訪問次數超過 1次 
  另外,還應當儘量的減小對對象以及數組深度查找。

(6). 字符串拼接

在 Javascript中使用」+」號來拼接字符串效率是比較低的,由於每次運行都會開闢新的內存並生成新的字符串變量,而後將拼接結果賦值給新變量。與之相比更爲高效的作法是使用數組的 join方法,即將須要拼接的字符串放在數組中最後調用其 join方法獲得結果。不過因爲使用數組也有必定的開銷,所以當須要拼接的字符串較多的時候能夠考慮用此方法。

十、CSS選擇符優化

在大多數人的觀念中,都以爲瀏覽器對 CSS選擇符的解析式從左往右進行的,例如 
#toc A { color: #444; }這樣一個選擇符,若是是從右往左解析則效率會很高,由於第一個 ID選擇基本上就把查找的範圍限定了,但實際上瀏覽器對選擇符的解析是從右往左進行的。如上面的選擇符,瀏覽器必須遍歷查找每個 A標籤的祖先節點,效率並不像以前想象的那樣高。根據瀏覽器的這一行爲特色,在寫選擇符的時候須要注意不少事項,有興趣的童鞋能夠去了解一下。

CDN加速

CDN(contentdistribute network,內容分發網絡)的本質仍然是一個緩存,並且將數據緩存在離用戶最近的地方,使用戶以最快速度獲取數據,即所謂網絡訪問第一跳,以下圖。

 

因爲CDN部署在網絡運營商的機房,這些運營商又是終端用戶的網絡服務提供商,所以用戶請求路由的第一跳就到達了CDN服務器,當CDN中存在瀏覽器請求的資源時,從CDN直接返回給瀏覽器,最短路徑返回響應,加快用戶訪問速度,減小數據中心負載壓力。 
CDN緩存的通常是靜態資源,如圖片、文件、CSS、script腳本、靜態網頁等,可是這些文件訪問頻度很高,將其緩存在CDN可極大改善網頁的打開速度。

反向代理

傳統代理服務器位於瀏覽器一側,代理瀏覽器將http請求發送到互聯網上,而反向代理服務器位於網站機房一側,代理網站web服務器接收http請求。以下圖所示:

 

論壇網站,把熱門詞條、帖子、博客緩存在反向代理服務器上加速用戶訪問速度,當這些動態內容有變化時,經過內部通知機制通知反向代理緩存失效,反向代理會從新加載最新的動態內容再次緩存起來。

此外,反向代理也能夠實現負載均衡的功能,而經過負載均衡構建的應用集羣能夠提升系統整體處理能力,進而改善網站高併發狀況下的性能。

相關文章
相關標籤/搜索