關於web前端網站最佳化

來源:互聯網
上載者:User

標籤:成員   接收   .net   訪問   應該   soft   瀏覽器   產生   流量   

不知道是哪位大牛的文章,轉過來嘻嘻。

斯迪
連結:https://www.zhihu.com/question/21658448/answer/18903129
來源:知乎
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

前端是龐大的,包括 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來做請求驗證。儘可能的讓資源能夠在緩衝中待得更久。關於 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. 避免重複的資源請求
  這種情況主要是由於疏忽或頁面由多個模組拼接而成,然後每個模組中請求了同樣的資源時,會導致資源的重複請求

  二、代碼級最佳化
  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中的資料訪問包括直接量 (字串、Regex )、變數、對象屬性以及數組,其中對直接量和局部變數的訪問是最快的,對對象屬性以及數組的訪問需要更大的開銷。當出現以下情況時,建議將資料放入局部變數:
  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 的這些“金科玉律 

關於web前端網站最佳化

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.