很多人通常在完成了產品之後才會去考慮性能。把與性能相關的事情拖到項目的最後來做,所做的也不過是對伺服器上的config文件進行一些微調、串聯、優化以及部分特別小的調整。而現在,技術已經有了翻天覆地的變化。一個項目的性能是非常重要的,除了要在技術層面上注意,更要在項目的設計之初就開始考慮,這樣才可以使性能的各種隱形需求完美的整合到項目中,隨著項目一起推進。

在性能方面,前端的優化是大家很容易忽視卻又十分重要的一點。

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

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

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

前端優化的途徑有很多,按粒度大致可以分為三類:

第一類是頁面級別的優化,例如 HTTP請求數、腳本的無阻塞載入、內聯腳本的位置優化等 ;

第二類是伺服器端優化,如:添加Expires 或Cache-Control報文頭等;

第三類則是代碼級別的優化,例如 Javascript 中的DOM 操作優化、CSS選擇符優化、圖片優化以及 HTML結構優化等等。

首先,我把雅虎14條優化原則,《高性能網站建設指南》以及《高性能網站建設進階指南》中提到的優化點做一次梳理,按照優化方向分類,可以得到這樣一張表格:

【頁面級優化】

一、減少 HTTP請求數

80%的響應時間花在下載網頁內容(images, stylesheets, javascripts, scripts, flash等)。減少請求次數是縮短響應時間的關鍵!可以通過簡化頁面設計來減少請求次數,但頁面內容較多可以採用以下技巧。

1)捆綁文件 現在有很多現成的庫可以幫你將多個腳本文件捆綁成一個文件,將多個樣式表文件捆綁成一個文件,以此來減少文件的下載次數。

2)CSS Sprites 就是把多個圖片拼成一副圖片,然後通過CSS來控制在什麼地方具體顯示這整張圖片的什麼位置。咱們來看一個真實的應用案例,如圖1:

從圖1可以看到這個應用的所有css和js都沒有沒有合併壓縮,我算了一下,總共引入了50個css和js,咱們再開看看圖2:

從圖2可以看出,一個頁面載入最少要4秒,每個css資源http請求就用了兩百多毫秒,50個資源就佔了一秒多。如果把所有js和css分別合併壓縮成一個文件,頁面的載入速度就會提高很多。

現在壓縮合併js和css的工具很多,但是考慮到現在好多項目都是maven工程,所以推薦大家使用雅虎的yuicompressor工具進行壓縮合併,還可以打出API文檔(jresui的API文檔就是用這個來打的), yuicompressor除了支持maven方式,也支持後台java代碼方式進行合併壓縮,具體配置如下:

▲將外部腳本置底,將CSS放在head中

瀏覽器是可以並發請求的,這一特點使得其能夠更快的載入資源,然而外鏈腳本在載入時卻會阻塞其他資源。如果將腳本放在比較靠前的位置,則會影響整個頁面的載入速度從而影響用戶體驗。解決這一問題的方法有很多,而最簡單可依賴的方法就是將腳本儘可能的往後挪,減少對並發下載的影響。

如果將 CSS放在其他地方比如 BODY中,則瀏覽器有可能還未下載和解析到 CSS就已經開始渲染頁面了,這就導致頁面由無 CSS狀態跳轉到 CSS狀態,用戶體驗比較糟糕。除此之外,有些瀏覽器會在 CSS下載完成後才開始渲染頁面,如果 CSS放在靠下的位置則會導致瀏覽器將渲染時間推遲。

二、靜態資源緩存我們知道,緩存對於前端性能的優化是十分重要的,在正式發布系統的時候,對於那些不經常變動的靜態資源比如各種JS、CSS文件、背景圖片等等我們會設置一個比較大的緩存過期時間(max-age),當用戶再次訪問這個頁面的時候就可以直接利用緩存而不是重新從伺服器獲取,這樣不僅可以減輕服務端的壓力,還可以節約網路傳輸的流量,同時用戶體驗也更好(用戶打開頁面更快了)。

一般的公司對於靜態資源以及緩存的處理方式無非就這麼幾種:1、 在靜態資源後面加一個版本號 v=1.111

2 、 為了準確的確定文件是否修改,將後面的版本號修改為文件摘要(主要根據文件內容生成的一個值)

以上兩種處理方式,都會存在一些問題。

第一種方式,需要維護版本號,如果在一個文件中,存在多個資源,那麼沒有被修改過的資源文件也會被修改版本號,導致不必要的資源載入。

第二種方式,可以精確的發現哪一個文件被修改過。從而要求客戶端進行重新載入。但是同樣會存在一些問題。

如果先發 html文件: 那麼會導致重新載入資源,但一樣還是無法訪問到最新的特性。(畢竟資源文件還沒有真正的更新。),如是Html頁面的結構有更新,但載入了舊的資源,很有可能導致頁面結構的錯亂。並且會緩存資源,直到資源過期,否則除非強制刷新,會一直是錯誤頁面。(這裡要注意到,由於第一次載入了舊的資源,版本號又是新的版本號,所以即使在這之後上了資源,這裡依舊會讀取舊的資源。

如果先發資源文件:

如果之前訪問過頁面,那就會有保存有本地緩存,那麼由於訪問的還是緩存文件,不會出現問題。但如果是新用戶,那麼就會訪問到新的資源文件,很有可能導致頁面錯亂。而等到頁面html也發布之後,頁面又恢復了正常。

所以還是建議大家通過nginx來配置靜態資源緩存過期時間來處理,大概配置如下:location ~ .*.(js|css)$ {expires 30d;}

三、非同步執行 (inline)內部腳本inline腳本對性能的影響與外部腳本相比,是有過之而無不及。首先,與外部腳本一樣, inline腳本在執行的時候一樣會阻塞並發請求,除此之外,由於瀏覽器在頁面處理方面是單線程的,當 inline腳本在頁面渲染之前執行時,頁面的渲染工作則會被推遲。簡而言之, inline腳本在執行的時候,頁面處於空白狀態。鑒於以上兩點原因,建議將執行時間較長的 inline腳本非同步執行,非同步的方式有很多種,例如使用 script元素的defer 屬性(存在兼容性問題和其他一些問題,例如不能使用 document.write)、使用setTimeout ,此外,在HTML5中引入了 Web Workers的機制,恰恰可以解決此類問題。

四、(Lazy Load)非同步載入 Javascript

隨著 Javascript框架的流行,越來越多的站點也使用起了框架。不過,一個框架往往包括了很多的功能實現,這些功能並不是每一個頁面都需要的,如果下載了不需要的腳本則算得上是一種資源浪費 -既浪費了帶寬又浪費了執行花費的時間。目前的做法大概有兩種,一種是為那些流量特別大的頁面專門定製一個專用的 mini版框架,另一種則是 Lazy Load。YUI 則使用了第二種方式,在 YUI的實現中,最初只載入核心模塊,其他模塊可以等到需要使用的時候才載入。

五、非同步請求 Callback非同步請求 Callback(就是將一些行為樣式提取出來,慢慢的載入信息的內容)在某些頁面中可能存在這樣一種需求,需要使用 script標籤來非同步的請求數據。類似:

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

六、減少不必要的 HTTP跳轉

對於以目錄形式訪問的 HTTP鏈接,很多人都會忽略鏈接最後是否帶 』/,假如你的伺服器對此是區別對待的話,那麼你也需要注意,這其中很可能隱藏了 301跳轉,增加了多餘請求。避免重複的資源請求這種情況主要是由於疏忽或頁面由多個模塊拼接而成,然後每個模塊中請求了同樣的資源時,會導致資源的重複請求

七、減少cookie傳輸

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

八、減少iframe數量使用iframe要注意理解iframe的優缺點:▲優點? 可以用來載入速度較慢的內容,例如廣告。? 安全沙箱保護。瀏覽器會對iframe中的內容進行安全控制。? 腳本可以並行下載

▲缺點

? 即使iframe內容為空也消耗載入時間? 會阻止頁面載入

本章節我們用頁面級來介紹如何進行性能優化,下個章節會從伺服器和代碼級來詳細介紹前端優化的實踐和案例。請持續關注!

推薦閱讀:

終極掃盲!網站必備的HTTPS協議和SSL證書,你真的了解透徹嗎? - 信息安全 - 恒生研究院?

rdc.hundsun.com

前端性能提升秘笈! - 開發專欄 - 恒生研究院?

rdc.hundsun.com
圖標

推薦閱讀:
相关文章