前端開(kāi)發(fā):5173首頁(yè)前端性能優(yōu)化實(shí)踐 |
發(fā)布時(shí)間: 2012/7/24 9:23:17 |
從制定計(jì)劃,到前后端的開(kāi)發(fā),最后到測(cè)試以及上線(xiàn),歷時(shí)4個(gè)月,5173首頁(yè)前端性能優(yōu)化項(xiàng)目終于順利上線(xiàn),并達(dá)到了預(yù)期的性能優(yōu)化目標(biāo)。這次的項(xiàng)目并不是改版,而是原來(lái)首頁(yè)的設(shè)計(jì)和功能不變,只做重構(gòu)和優(yōu)化。雖然項(xiàng)目名叫前端的性能優(yōu)化,但也并不僅僅是前端單方面的工作,要想徹底的把優(yōu)化做好,就需要前后端的通力配合。 歷史背景 老首頁(yè)應(yīng)該是09年上線(xiàn)的,首頁(yè)也是各部門(mén)爭(zhēng)奪資源的地方,大家都想在首頁(yè)有一席之地,各部門(mén)在首頁(yè)都有各自的小豆腐塊,如果有新項(xiàng)目的上線(xiàn),大多是打補(bǔ)丁的方式,并且唯一的規(guī)范就是能保證功能正常運(yùn)行,至于性能方面,那是很遙遠(yuǎn)的事。苦逼的是開(kāi)發(fā)人員,每次有首頁(yè)的修改都是擔(dān)驚受怕的,怕改了這個(gè)那個(gè)又出問(wèn)題,歷史原因造成的問(wèn)題越來(lái)越多。 最先看不下去的應(yīng)該是前端人員,因?yàn)槭醉?yè)在不斷的修修補(bǔ)補(bǔ)中,性能已經(jīng)差到前端人員覺(jué)得很沒(méi)面子的地步了。但是看不下去也僅僅是看不下去,沒(méi)法采取實(shí)質(zhì)性的措施來(lái)改善,因?yàn)檫@牽涉到各部門(mén)的利益,也如上面說(shuō)的,優(yōu)化不僅僅在于前端,于是前端人員也只能向上面反映問(wèn)題。到了今年,終于領(lǐng)導(dǎo)也看不下去了,某領(lǐng)導(dǎo)在海外訪(fǎng)問(wèn)我司的818和5173首頁(yè),對(duì)比起來(lái)前者首頁(yè)很快(插播一句,818首頁(yè)前端開(kāi)發(fā)人員也正是我^_^),后者首頁(yè)很慢,差別較大。于是在領(lǐng)導(dǎo)重視的推動(dòng)下,5173首頁(yè)的前端性能優(yōu)化項(xiàng)目才經(jīng)過(guò)批準(zhǔn),開(kāi)發(fā)人員終于可以放手大膽的折騰了。 問(wèn)題分析 在動(dòng)手前要制定計(jì)劃,制定計(jì)劃要從解決實(shí)際問(wèn)題出發(fā),先來(lái)看看老首頁(yè)的問(wèn)題,這是我在制定計(jì)劃時(shí)收集的相關(guān)數(shù)據(jù): 1、請(qǐng)求數(shù)過(guò)多,其中CSS外鏈數(shù)有12個(gè),JavaScript外鏈數(shù)竟有41個(gè); 2、頁(yè)面總體積過(guò)大,很多靜態(tài)資源都沒(méi)加gzip,動(dòng)態(tài)站點(diǎn)的JS甚至都沒(méi)有壓縮過(guò); 3、資源占用嚴(yán)重,在IE6下滾動(dòng)頁(yè)面時(shí)CPU占用率高達(dá)80%以上,內(nèi)存泄漏也很?chē)?yán)重; 4、廣告系統(tǒng),廣告圖片都是以document.write的方式在加載,頁(yè)面堵塞的情況很?chē)?yán)重; 5、頁(yè)面有7個(gè)iframe; 6、數(shù)據(jù)源接口混亂; 7、頁(yè)面加載速度過(guò)慢,有白屏現(xiàn)象,首屏完成加載很慢; 上面的數(shù)據(jù)讓你很震驚,這也說(shuō)明了有很大的優(yōu)化空間。找出了問(wèn)題所在,接下來(lái)才有具體的實(shí)施方向。總之,無(wú)論是常規(guī)的方法,亦或是奇淫技巧,目標(biāo)只有三個(gè)字,“快,更快”。 具體實(shí)施 雖然粗看頁(yè)面的內(nèi)容并不是很多,但是具體到功能模塊,都是很費(fèi)時(shí)費(fèi)力的。我們老大有一句很經(jīng)典的話(huà),“通常我會(huì)問(wèn)面試人員一個(gè)問(wèn)題,如果你獨(dú)自來(lái)做5173首頁(yè)的前端工作,多久能完成?如果答案只有一個(gè)星期,要么是沒(méi)看過(guò)頁(yè)面,要么就是很不專(zhuān)業(yè)。”我就獨(dú)自花了一個(gè)多月的時(shí)間才完成首頁(yè)的前端開(kāi)發(fā)工作。下面來(lái)說(shuō)說(shuō)具體的實(shí)施吧。 HTML&CSS 的重構(gòu) 頁(yè)面的設(shè)計(jì)和功能沒(méi)有變動(dòng),但是HTML頁(yè)面還是要做徹底的重構(gòu),這里我也嘗試了使用 HTML5 的新標(biāo)簽來(lái)對(duì)頁(yè)面進(jìn)行布局。CSS 的重構(gòu)也是理所當(dāng)然的,原來(lái)有12個(gè)外鏈的 CSS,這些都要統(tǒng)統(tǒng)干掉的,有些模塊如果不止首頁(yè)有用到,就需要模塊化,該放到公用文件就放到公用文件中,在開(kāi)發(fā)的時(shí)候可以分多個(gè)模塊,然后使用 @import到一個(gè)文件中,打包發(fā)布的時(shí)候再合并成一個(gè)文件。這需要把握好一個(gè)度,即要合理利用緩存,又要避免單文件過(guò)大,同時(shí)也要做好模塊化。 老首頁(yè)有很多 CSS 選擇器過(guò)長(zhǎng)的問(wèn)題,可能一個(gè) CSS 選擇器的組合長(zhǎng)達(dá)6-7個(gè)也是常有的事,CSS 選擇器過(guò)長(zhǎng)不僅僅是性能方面的影響,同時(shí)也因?yàn)?CSS 權(quán)值的關(guān)系,給后期維護(hù)帶來(lái)了很多的麻煩。應(yīng)該多使用 class 來(lái)定義選擇器,再加上 tag 選擇器的組合,最多3個(gè)選擇器的組合就能滿(mǎn)足絕大多數(shù)的需求了,另外在 CSS 的編寫(xiě)方面禁止使用 id 選擇器和 !important,養(yǎng)成良好的 CSS 編寫(xiě)習(xí)慣很重要。 JavaScript 的重構(gòu) JavaScript的重構(gòu)太迫切了,原來(lái)竟有41個(gè)JavaScript 外鏈文件,當(dāng)然這些外鏈也包括了15個(gè)廣告的外鏈,廣告的優(yōu)化我稍后再說(shuō),但是還剩下26個(gè)外鏈 JavaScript。這些臃腫不堪的 JavaScript文件即是造成頁(yè)面加載堵塞的元兇,也是系統(tǒng)資源占用的蛀蟲(chóng),這是整個(gè)項(xiàng)目的難點(diǎn)之一。 重新梳理了四級(jí)聯(lián)動(dòng)搜索的業(yè)務(wù)邏輯,并對(duì)四級(jí)聯(lián)動(dòng)搜索的交互功能做優(yōu)化,增強(qiáng)用戶(hù)體驗(yàn)。這個(gè)模塊的 ajax 交互功能較多,最大的 JSON 數(shù)據(jù)包竟然有94.4KB,此時(shí)合理的利用當(dāng)前頁(yè)面的緩存功能($.fn.data)很重要。體積最大的 JSON 數(shù)據(jù)包在頁(yè)面 Dom Ready 后進(jìn)行加載,然后拼裝第一屏的 HTML 代碼并緩存,當(dāng)用戶(hù)按字母索引選擇游戲的時(shí)候再到已加載完的 JSON 數(shù)據(jù)包中尋找相應(yīng)的數(shù)據(jù)去拼裝 HTML 代碼,然后緩存該索引的 HTML 代碼。如果接下來(lái)再選擇區(qū)、服、交易類(lèi)型時(shí),再到服務(wù)器去取相應(yīng)的 JSON 數(shù)據(jù),拼裝成 HTML 代碼后進(jìn)行緩存,此時(shí)只緩存最后一次的選擇結(jié)果。 便民中心也同樣是首頁(yè)業(yè)務(wù)邏輯很復(fù)雜的模塊,涉及到很多的ajax交互以及表單的操作。各個(gè)TAB中的表單是根據(jù)請(qǐng)求的JSON數(shù)據(jù)來(lái)生成HTML結(jié)構(gòu)的,原來(lái)是每次點(diǎn)擊TAB都會(huì)請(qǐng)求一次數(shù)據(jù),然后生成HTML結(jié)構(gòu),每切換一次TAB都要請(qǐng)求,再生成,這真得很二。同樣的數(shù)據(jù)和結(jié)構(gòu)只要請(qǐng)求一次,并生成一次即可,這種重復(fù)的操作是赤裸裸的浪費(fèi)資源。該模塊的JavaScript原來(lái)請(qǐng)求的動(dòng)態(tài)站點(diǎn)的文件,沒(méi)有做緩存也沒(méi)做過(guò)壓縮,每次頁(yè)面加載都在這里阻塞一小會(huì)。這里的服務(wù)端的數(shù)據(jù)源接口也很亂,開(kāi)發(fā)人員缺乏規(guī)范化數(shù)據(jù)接口的概念。這里的諸多問(wèn)題,我已無(wú)力吐槽了。最后也是重新梳理蛋痛的業(yè)務(wù)邏輯,重構(gòu)代碼。 延遲加載,提升首屏的加載速度 當(dāng)用戶(hù)打開(kāi)一個(gè)很長(zhǎng)的網(wǎng)頁(yè)時(shí),首屏內(nèi)容的加載給了最直觀的速度體驗(yàn)。所以,讓首屏盡快的完成加載也是用戶(hù)衡量該頁(yè)面是否夠“快”的最主要的因素。5173的首頁(yè),圖片基本都集中在下面的位置,讓下面的這些圖片全部都延遲加載就可以盡可能快的提升首屏的加載速度。常見(jiàn)的圖片延遲加載技術(shù)想必大家都不會(huì)陌生了,這里就不復(fù)述。在 TAB 內(nèi)容中也同樣有很多圖片,這里也讓它們?cè)谟|發(fā) TAB 菜單的時(shí)候再進(jìn)行加載。給圖片在HTML代碼中添加固定的尺寸自然也不再話(huà)下。so easy? no! 圖片中不僅僅有業(yè)務(wù)配置的圖片,也有來(lái)自第三方廣告系統(tǒng)的圖片(包括首屏的輪播大圖也是此類(lèi)型的)。這些廣告圖片的 URL 是一個(gè) JavaScript 鏈接,其中包含了使用 document.write 的方式來(lái)加載廣告圖片的代碼。還有些 TAB 中包含了使用 iframe 嵌入到頁(yè)面的合作站點(diǎn)的內(nèi)容。廣告圖片以及 iframe 都是阻塞頁(yè)面加載的元兇。 最初的想法是重新開(kāi)發(fā)一套廣告系統(tǒng),換一種廣告加載方式,但是開(kāi)發(fā)成本太高。最后想到了使用 textarea 來(lái)延遲加載廣告和 iframe,玉伯提供的這種方法確實(shí)挺好用的。textarae 是個(gè)好東西,不論是普通的 HTML 代碼亦或是 CSS、JavaScript 代碼,都可以扔到里面去實(shí)現(xiàn)延遲加載。廣告圖片的優(yōu)化比較麻煩,我在另一篇文章中有詳細(xì)的介紹。有了 textarea,很多內(nèi)容都可以像實(shí)現(xiàn)圖片延遲加載那樣來(lái)實(shí)行延遲加載,在 TAB 內(nèi)容中的 iframe 也可以在觸發(fā) TAB 菜單時(shí)再去加載 iframe。 正是這些各種延遲加載內(nèi)容的奇淫技巧在最大限度上提升了網(wǎng)頁(yè)首屏的加載速度。但是延遲加載內(nèi)容帶來(lái)的副作用需要說(shuō)明,對(duì)于一些比較重要的內(nèi)容,需要考慮到對(duì) SEO 的影響。 服務(wù)端的優(yōu)化 前端能做得基本都說(shuō)完了,再來(lái)說(shuō)說(shuō)服務(wù)端的優(yōu)化工作吧。原來(lái)服務(wù)端提供給前端的數(shù)據(jù)源都是從各個(gè)站點(diǎn)過(guò)來(lái)的,前端需要跟各個(gè)部門(mén)的開(kāi)發(fā)人員打交道,并且他們提供的數(shù)據(jù)源在性能上也比較慢。經(jīng)過(guò)協(xié)商決定將各數(shù)據(jù)源匯總到一臺(tái)中間服務(wù)器上,前端統(tǒng)一從這臺(tái)中間服務(wù)器中去取數(shù)據(jù),服務(wù)器端之間的通訊都加上一定的緩存時(shí)間,這樣就解決了數(shù)據(jù)源慢和不統(tǒng)一的問(wèn)題。 針對(duì)頁(yè)面總體積過(guò)大的問(wèn)題,代碼的重構(gòu)確實(shí)能減小不少的體積,另外靜態(tài)資源一律都要添加gzip,僅僅是添加gzip,帶來(lái)的性能提升也是比較明顯的。 合理的利用瀏覽器端的緩存也是很重要的,除了登錄信息以及 cookie 的這種時(shí)效性較高的請(qǐng)求外,所有能添加 cache-control 的請(qǐng)求都加上了 max-age 的過(guò)期時(shí)間。關(guān)于瀏覽器端的緩存添加,這里有一篇比較詳細(xì)的文章 Cache them if you can。緩存的添加也會(huì)給更新帶來(lái)麻煩,所以要有相應(yīng)的方法來(lái)清除緩存,給靜態(tài)資源的請(qǐng)求加上時(shí)間戳即可。 另外服務(wù)端這次也大膽的采用了 varnish 作為緩存加速服務(wù)器,這在國(guó)內(nèi)大型網(wǎng)站中應(yīng)該還不多見(jiàn)。 優(yōu)化成果 做了這么多工作是時(shí)候看看優(yōu)化成果了,先來(lái)看一組數(shù)據(jù)對(duì)比: 優(yōu)化前后的請(qǐng)求數(shù)對(duì)比: 請(qǐng)求數(shù)的大大減少,緩解了服務(wù)器的壓力,可以撤掉很多服務(wù)器了。 優(yōu)化前后的靜態(tài)資源的文件體積對(duì)比,沒(méi)有包含ajax數(shù)據(jù)等其他文件體積: 從文件體積的對(duì)比來(lái)看,優(yōu)化后節(jié)省了494KB的下載量,假若按照日PV1000000(估值,實(shí)際值遠(yuǎn)大于該值,實(shí)際值不便透露)來(lái)進(jìn)行計(jì)算,那么每天就可以節(jié)省流量470GB。 優(yōu)化前后的加載時(shí)間對(duì)比,這是在同樣的網(wǎng)絡(luò)環(huán)境下同時(shí)測(cè)試了淘寶和拍拍來(lái)進(jìn)行對(duì)比,測(cè)試軟件為基于 IE9 的 webWatch,每次測(cè)試都是清除緩存,分多次測(cè)試得到的一個(gè)平均值: 關(guān)于加載速度的分析,淘寶和拍拍的首屏的圖片較多,所以首屏的速度快,但是總加載時(shí)間要長(zhǎng)很多,當(dāng)然他們的下載量也要大很多,5173的首屏是DOM數(shù)較多,下載量也小很多,所以總時(shí)間和首屏?xí)r間相當(dāng)接近。這里說(shuō)得總下載量是頁(yè)面初次加載完成的總下載量,由于都用到延遲加載技術(shù),向下滾動(dòng)時(shí)又會(huì)有圖片加載,這些時(shí)間是不計(jì)算在內(nèi)的。 到底應(yīng)該如何來(lái)衡量網(wǎng)頁(yè)加載的快慢?此次的優(yōu)化我沒(méi)有用 yslow 和 pagespeed 等測(cè)試分?jǐn)?shù)的軟件,而是以實(shí)際的加載速度為優(yōu)化的目標(biāo),首屏的加載速度提升就是最符合實(shí)際的說(shuō)明。如果一個(gè)網(wǎng)站打開(kāi)半天還是白屏,相信大多數(shù)人都會(huì)覺(jué)得很慢。這就是實(shí)際的體驗(yàn),測(cè)分軟件是反映不出來(lái)的。 本文出自:億恩科技【1tcdy.com】 服務(wù)器租用/服務(wù)器托管中國(guó)五強(qiáng)!虛擬主機(jī)域名注冊(cè)頂級(jí)提供商!15年品質(zhì)保障!--億恩科技[ENKJ.COM] |