性能優化淺談
這次總結主要關于性能優化探索心得。水平很淺,只是說說自己的學習收獲。
************這里開始了*************
看過的前端開發書籍都在說這四個字,性能優化的字面解釋是:不影響系統運行正確性的前提下,使之運行地更快,完成特定功能所需的時間更短。這句話可以看出性能優化的目的:更快的速度、更少的時間。
1)性能優化有什么意義?
谷歌的數據表明,一個有10條數據0.4秒可以加載完的頁面,在變成30條數據加載時間為0.9秒后,流量和廣告收入減少了20%。當谷歌地圖的首頁文件大小從100kb減少到70~80kb時,流量在第一周漲了10%,接下來的三周漲了25%。騰訊的前端工程師根據長期的數據監控也發現頁面的一秒鐘延遲會造成9.4%的PV的下降,8.3%跳出率的增加以及3.5%轉化率的下降。這兩家公司都是行業的翹楚,具有極其巨大的用戶群,這些數據足夠讓我們重視性能優化。近八成的用戶可以忍受的響應時間為5秒,500PC的主站打開資源加載完畢的時間為5.67s,QQ彩票為12.75s,網易彩票為16.79,看到這里還是很驕傲的*_*。
2)如何優化?
資料顯示和瀏覽器調試分析發現,頁面的打開速度關系密切的三個原因:寬帶速率(俗稱網速),web服務器,頁面結構。可參加表1:
表1.主要影響打開速度的四個因素分析
主要影響因素 |
作用原理 |
影響 |
寬帶速率 |
接收響應、連接速度減慢 |
連接變慢 |
服務器 |
寬帶限制或者服務器請求響應最大限制、硬盤故障、網卡故障 |
等待時間延長 |
頁面結構 |
導致重繪和白板屏 |
用戶體驗 |
-----服務器-----
就如對著大山吶喊等自己的回音,頁面打開瀏覽器和服務器(單指web服務器)之間通過http協議進行通信的過程。服務器的影響也分為服務器性能和硬件配置。這里可以簡單看下瀏覽器加載渲染網頁的過程見圖1:
圖1.瀏覽器的工作原理
由圖可知瀏覽器中有一個請求的鏈接www.500.com,DNS解析查到映射的IP地址(記為A)192.168.18.58,然后瀏覽器向這個IP地址連接,連接成功后將請求頭信息通過http協議向A所在的服務器web servers發起請求,服務器接收并等待處理,處理后響應給瀏覽器。這個時候瀏覽器開始顯示html代碼,并獲取css/image/js的地址,再次向DNS發起請求并獲得后開始渲染頁面(我們熟悉的樣式和動效等實現)。這是邏輯上的,實際上的情況可以在瀏覽器的調試器俗稱web檢查器(目前只有Safari的Web Inspector,IE的開發人員工具、火狐的FireBug、Opera的Dragonfly)上看見。此處使用火狐的firebug,在搜索欄輸入www.500.com后,截取其中一個請求的時長詳情如圖2所示:
圖2.500彩票主站某次請求的時間詳情
由圖可見域名解析從16ms開始持續了0ms,連接到ip從16ms開始持續了31ms,發送給ip所在服務器用了0ms,等待服務器(想知道為什么要等待?可以參看結尾的附言)響應用了47ms,傳回接收數據用了0ms。服務器的影響對于前端來說占據了很大的加載時間,但是這也客觀取決于服務器和后臺的DB設計,我們似乎有些手足無措。但是關于http請求數確是前端可以做的。
如何減少http請求?根據上面的分析我們會知道image、css、js鏈接都會發出http請求,我們會自然的想到合并資源。事實上我們也是這樣做的,圖片可以用圖片精靈進行處理,css可以合并為<2個(style.css,public.css),js合并為一個。圖2是500主站一張合并后的圖片:
圖3.500主站合并后的圖片
剛開始做項目的時候為了更加清晰的看樣式文件,我將css分為base.css,public.css,style.css,header.css...我得承認這樣確實可以幫助我看樣式結構,但是后來我才知道我犧牲了對用戶有利的寶貴的加載時間。現在自己也嚴格控制保持在2個css鏈接以下了。為了避免額外的js鏈接,將對時間幀要求不嚴格的動畫統一用css3寫,也是做的改變。現在想想最初分散的css列表,濫用的js鏈接,數量龐大的圖片簡直是災難。
-----寬帶速率-----
寬帶速率,簡單的說就是速率越大,上傳下載的速度越快。2014年統計的中國固網寬帶用戶平均上網速度為199.3kb/s,我們如果按照200kb/s計算,2M的寬帶的理論速度是256kb/s,可以發現中國網民的平均寬帶速率處于2M左右。
我們現在可以保持一個頁面的所有資源總和在500kb左右,那么我們的用戶使用時平均會花500/200=2.5s,如果網速更慢將會影響更大。
圖4.世界互聯網大會
今年12月16日在這江烏鎮召開的“第二屆世界互聯網大會”上習總書記發聲:中國正實施“寬帶中國”戰略,2020年全覆蓋(附美圖一張-_-)。對于寬帶速率的未來相對是樂觀的,但處于眼下的前端可以做的即是減少分母的數值,也即是我們的網頁總大小。
如何減少資源總量?浮現在腦海中的就是一個字:壓。寫頁面的時候壓代碼數量,做到盡量少的冗余。寫完后使用壓縮軟件進行代碼格式化圖片壓縮,減少總資源大小。
那么問題來了:不冗余的代碼的標準是什么?通常來說,一段程序能夠執行既定的任務,但是經過優化能夠同樣達到目的,而執行時間和代碼數量減少了,說明刪除的代碼就是程序的冗余代碼。在實際的項目中不在多個樣式名中使用大部分相同的樣式,重復樣式歸并到一個公共類、刪除沒用的標簽避免占位。總體來說不多余,不重復的代碼即是不冗余的。之前的項目中有時為了區分兩個DOM節點,我賦予節點空的標簽,也增加了資源總量。
-----頁面結構-----
頁面結構是指頁面中的元素排列順序。頁面結構會對加載速度造成影響是由于瀏覽器對頁面的讀取順序所致。由圖1可知,瀏覽器會先解析html代碼結構,然后再渲染頁面。而瀏覽器加載顯示html時是按照從上到下的順序進行的,渲染的順序也是從上到下,下載和渲染是同時進行的。遇到語義解釋性的標簽嵌入文件(JS腳本、css等)下載過程會啟用單獨連接進行下載。下載后進行解析,解析時停止所有元素的下載。解析完成后開始渲染。JS、CSS中如有重定義,后定義函數將覆蓋前定義函數。詳細的html頁面加載和解析流程如下圖所示:
圖5. html頁面加載和解析流程
由圖可知,html按照從上到下的順序解析和渲染頁面,正常情況下解析1次+渲染1次。有些瀏覽器為了減少重繪,會在css文件加載完成后渲染頁面,這時我們的用戶就會對著一個白屏思考人生~_~。大內容+低網速會加大白板的時間,為了保證用戶在頁面加載的時候至少可以看到一些東西,將css放在html頭部是一種照顧用戶的做法。js因為其對dom節點的操作性,則會出現不能與html并行下載解析的情形。即是如果腳本在頭部則會阻止頁面的渲染,用戶又要開始對著白板發呆了。雖然目前可以用DEFER屬性通知瀏覽器并行下載,部分瀏覽器可能不認識這個屬性加之DEFER的使用就禁止了docment.white().將js放在html的尾部可以從本質上解決腳本阻塞加載時間問題。
-----總結-----
1)減少http請求
2)合并資源(css,js,image)
3)壓縮圖片,代碼
4)減少重繪
5)CSS放在頭部,JS放在頁尾