很高興看到越來越多的企業重視前端開發了,前端不再是網站開發人員的附屬技能。回想我剛開始入行時,那時ASP網站(非ASP.NET)盛行,80%的網站都是用ASP來做的,一個網頁可能就是一個ASP文件,里面前端代碼和后端代碼混在一起。現在不同了,前后端分離,前端可以專注於展示了,不用太在意后端的實現。但是,因為前端發展太快,展示環境也復雜多變,需要前端開發者掌握更廣的知識。
這篇雜談,我打算從一個比較廣的面(包含JS,CSS,網絡傳輸,HTML5等),以化整為零為出發點,來和大家介紹一些前端優化的方法。(因為個人知識和經驗有限,除了文中提到的幾點,一定還有別的優化方法有化零為整的特性,歡迎大家一起補充哈,本文會不定期更新)
何為化零為整?通俗點說,就是我們將細碎的東西整合為一個整體,通過操作這個整體,也能達到逐個操作細碎東西的效果。比如,你給我四個蘋果,我雙手可以拿着到處走動;如果給我十個蘋果,我全兜手上,走起路來可能會慢些了,因為要照顧蘋果,怕掉了;但是,如果你再給我個袋子,我把十個蘋果裝里面,它們就成為一個整體,我就可以拎着到處跑了。
OK,說了這么一通,開始細數前端中需要化零為整的地方吧。
1.atlas/sprite assets/精靈圖/雪碧圖
這些都是對圖集合的稱呼,圖集合就是在做圖片資源的時候,將一些小的圖片元素集中做到一張圖片中。在使用時,通過一些參數,來顯示大圖集合中所需要那個圖片原素。比如,需要這個大圖的某個ICON來做為DIV的背景,則除了將這個大圖設為DIV的背景外,還需要更改背景圖的位置(position)來顯示具體某小圖。
例:某網站的sprite assets如下:
2.事件委托
面試時,我經常問的一個問題,有一個列表頁,頁面結構是外面一個BODY, 里面有一萬個子DIV,每個DIV里面有一些文字,這些文字都不相同。需求是,點擊一個DIV,要求彈個alert框,將DIV里的文字顯示出來。你會怎么做。
30%的人會用JQuery來綁事件,認為看着簡潔,應該效率高,如:$("body>div").click(……) ,有20%的人會寫原生的語句來遍歷,給每個DIV添加點擊事件,有10%的人回答,在頁面滾動時,存下頁面滾動的高度,在點擊時,獲取觸發點在屏幕的Y坐標,將Y的坐標和頁面滾動的高度相加,然后除以每個DIV的高度,就知道點了第幾個元素,再將這個元素的內容彈出來。(或其它類似的做法)
回答出以上答案的面試者在這題會被扣分,正確答案是,只用給外面的元素(本題是BODY)添加點擊事件,在點擊時,可以獲取到引發點擊事件的源元素(如某DIV),將這個元素的文本內容彈出來即可。
3.長連接 keep alive
這點和后端有關系了,不光是前端的事了。大多數網頁是用http方式來獲取資源(如圖片,樣式表文件,JS文件等),有部分服務器不會維持連接,來了個請求,就建立連接,然后輸出內容,輸出完后斷開連接,再重新建立下個請求的連接和輸出。如果一個網頁需要請求一百個文件,服務器就要建立和斷開一百次連接。每次建立和斷開都需要時間(甚至比傳輸數據時間還長),無疑增加了頁面的呈現時間。如果服務器啟用了keep alive,不光減輕了服務器負擔,也加快了頁面打開時間。
如下圖,我們可以看到,實際接收內容的時間(Receiving)是很短的,大部分時間花在了等待(Waiting)和阻塞(Blocking)。
4.多DOM合並
由於前端表現越來越豐富,頁面上東西也越來越多,隨之而來的問題是DOM太多了,在做一些DOM操作時,會帶來性能問題。在DOM非常多的情況下,我們有必要把DOM進行合並,可以考慮把多個DOM合並為少量幾個,或在可以的情況下,使用CANVAS來展示。
如:有些需求會要求前端開發者做這種日期選擇器
如果使用一個DOM來裝一個選項(如:1970),不考慮按鈕,單獨看日期選項的話,可能會需要44+12+31=87個DOM,對於移動瀏覽器來說,DOM越少越好。萬一產品后來一想,除了日期,還要添加時分秒選項呢?這就需要44+12+31+24+60+60=231個DOM了。但我們可以細想一下,如果把各字段(年、月、日)只用一個很高的容器(如DIV)來裝,內容可以用換行符來換行,取值時通過一些算法來得到,是不是大幅縮小了DOM數量?從87個DOM變為3個DOM。少了一個數量級。
5.WebSocket
很多網頁有實時更新數據的要求,如證券類網站。為了避免頁面刷新,會使用AJAX來進行長輪詢,每隔一段時間(如一秒鍾)就連一次服務器取下數據。這樣會造成大量的請求連接,不止給前端,也給后端帶來了不小的壓力。幸好HTML5給我們帶來了WebSocket,網頁能夠和服務器保持長連接,通過長連接來維持數據的實時更新了。
6.CSS屬性繼承
CSS會繼承父元素的屬性,我們可以將一些通用的屬性在父元素的CSS中定義,子元素通過繼承來獲取這些元素。在某些情況下,合理使用繼承能較明顯地縮小CSS文件的大小。
7.documentFragment
"一個列表頁,需要你往里面插入一千個DOM,你怎么做?" 這是我經常問別人的一道題。
很多時候,你往頁面中加一個DOM,就會引起頁面的重構。如果你使用遍歷來逐一添加,每添加一次,頁面都會重新渲染一次,這種做法會帶來性能的下降。好的方式是把要添加的元素先緩存起來, 要添加時一次性添加。一般會使用documentFragment來進行緩存,還有些使用長的字符串(HTML代碼串)來緩存。
8.多動畫合並為一個
在做CSS3的動畫時,如果需求中要求有多步驟的動畫(如,將一個DIV沿Y軸旋轉30度,接着沿X軸旋轉30度,再沿Z軸旋轉30度),我們可以將這些動畫合並,使用animation的關鍵幀來將這些步驟隔離。省去多步操作DOM的成本。
9.多文件壓縮與合並
對JS和CSS文件壓縮,是前端縮小網絡傳輸量的有效方式(壓縮的做法一般是去除多余空格和換行,以及替換變量名或方法名。YUI Compressor是個不錯的工具)
將多個小的JS或CSS文件合並(merge)為一個大文件,這種做法可以大幅減少請示的次數。
本文是博主Arfei Zhang原創,歡迎轉載。轉載請注明轉自博客園,並附上本文鏈接http://www.cnblogs.com/arfeizhang/p/optimization1.html ,謝謝!