前端優化

鏈接:前端優化

前端優化

瀏覽器發送HTTP請求,服務器收到請求全文後,返回HTTP響應,在瀏覽器接收之後結束這個過程。瀏覽器和服務器只有一次互動的機會,瀏覽器主動發起,而服務器被動地根據收到的請求內容返回結果。一個完整的請求都需要經過DNS尋址、與服務器建立連接、發送數據、等待服務器響應、接收數據的過程。

前端優化的途徑

  1. 頁面級別的優化,例如HTTP請求數、腳本的無阻塞加載、內聯腳本的位置優化等;
  2. 代碼級別的優化,例如JavaScript中的DOM操作優化、CSS選擇符優化、圖片優化以及HTML結構優化等。

頁面級優化

1. 減少HTTP請求數

減少HTTP請求數的主要途徑

1、從設計實現層面簡化頁面

保持頁面簡潔、減少資源的使用是最直接的。能使用CSS替代效果就儘量少使用圖片。

2、合理設置HTTP緩存

恰當地緩存設置可以大大減少HTTP請求。被緩存資源的請求服務器是304響應,只有Header沒有body,沒有節省帶寬。對於多個頁面都可能使用到的代碼,儘量拆分到同一個文件中。如果是嵌入頁面換來的是增大了頁面的體積,而且無法利用瀏覽器緩存。

3、資源合併和壓縮

如果可以,儘可能將外部的腳本、樣式進行合併,多個合爲一個。另外,CSS、JavaScript、image都可以用相應的工具進行壓縮。

4、CSS Sprites

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

5、lazy load image

這個策略實際上並不一定能減少HTTP請求數,但是卻能在某些條件下或者頁面剛加載時減少HTTP請求數。對於圖片而言,在頁面剛加載時可以只加載第一屏,當用戶繼續往後滾屏時才加載後續的圖片。以前的做法是在加載時把第一屏之後的圖片地址緩存在textarea標籤中,待用戶往下滾屏時才惰性加載。百度圖片和花瓣網也是用這種流行的瀑布流加載圖片。

2. 將外部腳本置底

外鏈腳本在加載時會阻塞其他資源,例如在腳本加載完成之前,它後面的圖片、樣式以及其他腳本都處於阻塞狀態,直到腳本加載完成後纔會開始加載。如果把腳本放在比較靠前的位置,則會影響整個頁面的加載速度從而影響用戶體驗。最簡單可依賴的方法是將腳本儘可能往後挪,減少對併發下載的影響。如果時效性允許的話,可以考慮在DOMLoaded事件觸發時加載,或者用setTimeout方式來靈活控制加載的時機。

3. 異步執行inline腳本

inline腳本對性能的影響比外部腳本大很多。首先,與外部腳本一樣,inline腳本在執行時也會阻塞併發請求,除此之外,由於瀏覽器在頁面處理方面時單線程的,當inline腳本在頁面渲染之前執行時,頁面的渲染工作則會被推遲。簡而言之,inline腳本在執行時頁面處於空白狀態。

鑑於以上兩點,建議將執行時間較長的inline腳本異步執行。異步執行的方式有很多種,例如使用script元素的defer屬性、使用setTimeout,此外,在HTML5中引入了web workers的機制,恰恰可以解決此類問題。

4. lazy load JavaScript

目前的做法大概有兩種,一種是爲流量特別大的頁面專門定製一個專用的mini版框架,另一種則是lazy load,最初只加載核心模塊,其他模塊可以等到需要使用的時候才加載,類似於javaswing,引入需要的組件庫文件。

5. 將CSS放在head

6. 減少不必要的HTTP跳轉

對於以目錄形式訪問的HTTP鏈接,很多人都會忽略鏈接最後是否帶/,假如服務器對此區別對待,那麼其中很可能隱藏了301跳轉,增加了多餘請求。

代碼級優化

1. JavaScript

1、DOM

DOM操作應該是腳本中最耗性能的一類操作,例如增、刪、查、改DOM元素或者對DOM集合進行操作。如果腳本中包含了大量的DOM操作則需要注意html collection

在腳本中document.imagesdocument.formsgetElementsByTagName()返回的都是HTMLCollection類型的集合,在平時使用的時候大多將它作爲數組來使用,因爲它有length屬性,也可以使用索引訪問每一個元素。不過在訪問性能上則比數組要差很多,原因這個集合並不是一個靜態的結果,它表示的僅僅是一個特定的查詢,每次訪問該集合時都會重新執行這個查詢從而更新查詢結果。所謂的訪問集合包括讀取集合的length屬性、訪問集合中的元素。

因此,當你需要遍歷HTML collection時,儘量將它轉爲數組後再訪問,以提高性能。即使不轉換爲數組,也請儘可能少地訪問它,例如在遍歷的時候可以將length屬性、成員保存到局部變量後再使用局部變量。

2、慎用with

with(obj){p=1};代碼塊的行爲實際上是修改了代碼塊中的執行環境,將obj放在了其作用於的最前端,在with代碼塊中訪問非局部變量都是先從obj上開始查找,如果沒有再依次按作用域鏈向上查找,因此使用with相當於增加了作用域鏈長度。而每次查找作用域鏈都是要消耗時間的,過長的作用域鏈會導致查找性能下降。

因此,除非你能肯定在with代碼中脂肪紋obj中的屬性,否則慎用with,替代的可以使用局部變量緩存需要訪問的屬性。

3、避免使用evalFunction

每次evalFunction構造函數作用於字符串表示的源代碼時,腳本引擎都需要將源代碼轉換爲可執行代碼。這是很消耗資源的操作——通常比簡單的函數調用慢100倍以上。

eval函數效率特別低,由於事先無法知曉傳給eval的字符串中的內容,eval在其上下文中解析要處理的代碼,也就是說編譯器無法優化上下文,因此只能有瀏覽器在運行時解析代碼,這對性能影響很大。

Function構造函數比eval略好,因爲使用此代碼不會影響周圍代碼,但其速度仍很慢。

此外,使用evalFunction不利於JavaScript壓縮工具執行壓縮。

4、減少作用域鏈查找

作用域鏈查找問題,這一點在循環中尤其需要注意。如果在循環中需要訪問非本作用域下的變量時請在遍歷之前用局部變量緩存該變量,並在遍歷結束後再重複那個變量,這一點對全局變量尤其重要,因爲全局變量處於作用域鏈的最頂端,訪問時的查找次數是最多的。

此外,要減少作用域鏈查找還應該減少閉包的使用。閉包的變量可能保存到內存中,內存消耗很大,解決方法是在退出函數前,將不使用的局部變量刪除。

5、數據訪問

JavaScript中的數據訪問包括直接量(字符串、正則表達式)、變量、對象屬性以及數組,其中對直接量和局部變量的訪問是最快的,對對象屬性以及數組的訪問需要更大的開銷。當出現以下情況時,建議將數據放入局部變量:

  1. 對任何對象屬性的訪問超過1次
  2. 對任何數組成員的訪問次數超過1次

另外,還應當儘可能的減少對對象以及數組深度查找

6、字符串拼接

在JavaScript中使用+號來拼接字符串效率是比較低的,因爲每次運行都會開闢新的內存並生成新的字符串變量,然後拼接結果賦值給新變量。之前使用jQuery+Ajax交互頁面,很多時候都是將後臺傳輸過來的數據和前端HTML結構拼接成字符串,然後呈現在頁面HTML容器裏。

與之相比更爲高效的做法是使用數組的join方法,即將需要拼接的字符串放在數組中最後調用其join方法得到結果。不過由於使用數組也有一定的開銷,因此當需要拼接的字符串較多時可以考慮使用此方法。

2. CSS選擇符

在大多數人的觀念中,都覺得瀏覽器對CSS選擇符的解析是從左往右進行的。

如果是從右往左解析則效率會很高,因爲第一個ID選擇基本上就把查找的範圍限定了,但實際上瀏覽器對選擇符的解析是從右往左進行的。#tag A {color: "#ccc";},瀏覽器必須遍歷查找每一個A標籤的祖先節點,效率並不像之前想象的那麼高。根據瀏覽器的這一行爲特點,在寫選擇符的時候需要注意很多事項。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章