做系統(tǒng)開(kāi)發(fā),不僅僅要關(guān)注前端的設(shè)計(jì),系統(tǒng)或產(chǎn)品的更新更加要跟得上時(shí)代的變化。優(yōu)化的對(duì)象不僅僅指產(chǎn)品本身,還有我們?nèi)粘5拈_(kāi)發(fā)流程。如果不做優(yōu)化,那么要么是你的產(chǎn)品過(guò)時(shí)了,要么是你的開(kāi)發(fā)效率太低,開(kāi)發(fā)的技術(shù)也會(huì)跟不上時(shí)代的節(jié)奏。因此,作為系統(tǒng)開(kāi)發(fā)/產(chǎn)品開(kāi)發(fā)的成員,我們必須有敏銳的觸覺(jué)和快速的優(yōu)化變身的能力,不然只會(huì)被淘汰在茫茫的互聯(lián)網(wǎng)大海之中。
下面我們一起跟著深圳市星翼創(chuàng)想網(wǎng)絡(luò)科技有限公司來(lái)閱讀以下文章,看看做前端開(kāi)發(fā)優(yōu)化究竟都經(jīng)歷了什么吧!
11.0時(shí)代
前期模塊化已經(jīng)做的不錯(cuò)了,至少不必花大量時(shí)間去重構(gòu)代碼。模塊劃分如下圖,邏輯層次上還是比較清晰。
前端模塊化依賴的主流庫(kù)也就數(shù)國(guó)內(nèi)的Seajs和國(guó)外的requirejs,這里就不陳述。采用了Seajs作為模塊管理器,zepto作為基礎(chǔ)庫(kù)文件,lib主要包含了項(xiàng)目中用到的主流第三方庫(kù)文件。
我們知道模塊化帶來(lái)的最大弊端便是HTTP請(qǐng)求數(shù)增加,所以上線的時(shí)候必須合并文件。下圖中的package模塊是文件大集合,打包了很多個(gè)JS模塊,除去上圖中的基礎(chǔ)庫(kù)文件和業(yè)務(wù)模塊層,在上線的時(shí)候大部分文件都被打包在package.js里。
大部分頁(yè)面的JS請(qǐng)求是這樣的:
細(xì)心點(diǎn)的同學(xué)可能注意到兩個(gè)問(wèn)題:文件的大小和加載時(shí)間。剛才的截圖還是在PC端截取的,手機(jī)和不同網(wǎng)絡(luò)環(huán)境的表現(xiàn)會(huì)更加糟糕。
現(xiàn)在來(lái)看下目錄
存在的問(wèn)題:
- 目錄看起來(lái)算規(guī)范,但實(shí)際上是公共的和業(yè)務(wù)的混在一塊。
- 大部分文件合并在一個(gè)文件,合并策略不合理。
- 由第二點(diǎn)引發(fā)的第三個(gè)問(wèn)題,發(fā)布上線時(shí),只要兩人發(fā)布涉及到package文件,沖突必然發(fā)生。
- 發(fā)布時(shí)需要down下上一次的文件,對(duì)照合并的新文件,以免發(fā)錯(cuò)。
- 注意,第四點(diǎn)是人工。一不小心發(fā)錯(cuò),或者把他人剛發(fā)布的文件覆蓋了,這種事情發(fā)生10+次。
- 只有一臺(tái)測(cè)試機(jī)器,測(cè)試環(huán)境經(jīng)常覆蓋是常事。
- 版本控制問(wèn)題,不以SVN為版本,而是預(yù)發(fā)布機(jī)器上代碼,管理混亂
不敢想象如果10+人的團(tuán)隊(duì)一起在這種模式下開(kāi)發(fā),會(huì)是怎樣的場(chǎng)面。
22.0時(shí)代
由第一個(gè)版本引起的問(wèn)題,著實(shí)讓人很蛋疼,每次開(kāi)發(fā)版本就是一次陣痛,尤其是測(cè)試、發(fā)布環(huán)節(jié)。所以就開(kāi)始慢慢著手解決。隨著業(yè)務(wù)擴(kuò)展,人員增多,就誕生了下面這個(gè)圖。
優(yōu)化措施:
- 調(diào)整模塊,讓共用的模塊更加共用,業(yè)務(wù)模塊跟隨業(yè)務(wù)自身。
- 更改模塊合并策略,既然大了,我就分成小,一定程度緩解了沖突。
- 替換原有的同步文件工具,包括測(cè)試與正式環(huán)境,接入ARS,提測(cè)發(fā)布流程順暢多了。
- ARS帶有沖突檢測(cè)功能,告別人工對(duì)照合并,覆蓋不再容易發(fā)生。
- 公共JS文件緩存在localstorage中,模擬manifest,帶版本號(hào)控制。
- 以SVN為板塊控制工具,不再對(duì)照外網(wǎng)代碼。
一些統(tǒng)計(jì)
localstorage本地緩存
localstorage緩存命中率
首屏?xí)r間
window.onload時(shí)間
一切看起來(lái)很美好,但是好景不長(zhǎng),因?yàn)樾碌膯?wèn)題又來(lái)了。
- 之前拆分package.js文件為多個(gè)文件,實(shí)際請(qǐng)求的時(shí)候則是合并了請(qǐng)求,包括JS文件和CSS文件。combo文件實(shí)際上會(huì)有延遲問(wèn)題,在發(fā)布的時(shí)間節(jié)點(diǎn)上存在不同步的問(wèn)題,直接導(dǎo)致頁(yè)面掛了。
- 拋開(kāi)combo文件不說(shuō),由于瀏覽器緩存的問(wèn)題,每次更新版本的時(shí)候要手動(dòng)加上一個(gè)時(shí)間戳,來(lái)規(guī)避緩存造成的錯(cuò)誤。也是個(gè)很蛋疼的點(diǎn)。
- 隨著業(yè)務(wù)增長(zhǎng),越來(lái)越多頁(yè)面是放在APP里面訪問(wèn)。觸屏頁(yè)面已經(jīng)不再是重點(diǎn),如何更好的利用APP加速頁(yè)面才是關(guān)注點(diǎn)。很多人想到了手Q的離線包,但聽(tīng)說(shuō)實(shí)踐起來(lái)也不是特別方便,我們就采用了客戶端緩存hash文件的策略,告別304。所以這里又涉及到自動(dòng)化。
- 雪碧圖基本是手工;
- 代碼混淆沒(méi)有壓縮;
CSS合并文件要手寫(xiě)地址,類似下面:
http://at.qq.com/min/f=cssv4/common/reset.css,cssv4/common/base.css,cssv4/module/btns.css,cssv4/module/tab.css,cssv4/module/app-list.css,cssv4/module/talk-bar.css,cssv4/module/popup.css,cssv4/page/game-detail.css,cssv4/page/talk.css,cssv4/module/comments-bar.css
33.0時(shí)代
為了解決上述問(wèn)題,流程需要進(jìn)一步優(yōu)化,簡(jiǎn)單點(diǎn)就是讓自動(dòng)化程度更提高。
3.1 探索期
前期在方案選擇上也做過(guò)一些討論,自己完全從底層寫(xiě)時(shí)間上不允許。之前折騰過(guò)Grunt發(fā)現(xiàn)并不是那么好用,后來(lái)發(fā)現(xiàn)百度的前端解決方案FIS能夠滿足我們的需求。
- 生成以hash值(后綴)命名的文件,代碼更改,生成新文件,且都會(huì)自動(dòng)更新HTML中的引用(核心訴求),就像下圖:
- 合并雪碧圖
- 壓縮混淆文件
- 文件合并(包括JS文件和CSS文件)
能 做到這幾點(diǎn)基本就滿足了我們的需求。前期的一切都是未知的,不太明白會(huì)遇到什么大問(wèn)題。乍看起來(lái)非常好用,如果簡(jiǎn)單的頁(yè)面,確實(shí)會(huì)很簡(jiǎn)單,只要簡(jiǎn)單幾行配 置就可以搞定,但到現(xiàn)在FIS的配置文件200+行。一些特性很難滿足,需要二次開(kāi)發(fā)。上手簡(jiǎn)單,要深入難,必須要看源碼改源碼,寫(xiě)插件,這大概就是用 FIS的心得。
前期想了要怎樣把開(kāi)發(fā)——測(cè)試——預(yù)發(fā)布——發(fā)布這個(gè)流程依賴工具流暢的跑起來(lái),大概構(gòu)思如下:
注:
- 調(diào)試、發(fā)布代碼與源代碼分離
- 本地調(diào)試用代理如fiddler,或者上開(kāi)發(fā)機(jī)
- deploy是構(gòu)建工具同步文件的一個(gè)功能
- 保證源碼的版本最新,發(fā)布代碼走ARS。
工程化進(jìn)展卻不是想象中的順利,實(shí)踐中遇到了一些問(wèn)題,也只能硬著頭皮咬著牙去解決。
3.2 煎熬期
沖突問(wèn)題
沖突問(wèn)題一直存在,在2.0時(shí)代不那么明顯罷了。原因是測(cè)試環(huán)境的JS已經(jīng)被合并過(guò)一次。
時(shí)間問(wèn)題
由于剛開(kāi)始文件比較少,構(gòu)建速度基本沒(méi)啥問(wèn)題。后來(lái)業(yè)務(wù)越來(lái)越多,參與的開(kāi)發(fā)也越來(lái)約多。文件暴增到4000+,構(gòu)建時(shí)間一步步增加。
開(kāi)發(fā)調(diào)試耗時(shí) 3987ms
發(fā)布構(gòu)建的時(shí)候因?yàn)橐M(jìn)行md5計(jì)算,文件壓縮等,要181745ms!已經(jīng)無(wú)法忍了。
ARS流程
用過(guò)ARS的同學(xué)肯定明白,流程還是比較蛋疼,要完成提交SVN,點(diǎn)擊同步等等一系列操作,繁瑣。
構(gòu)建命令
命令比較長(zhǎng),參數(shù)多,難以記憶
產(chǎn)出文件多,發(fā)布麻煩
每改動(dòng)一個(gè)字母,發(fā)布的時(shí)候就會(huì)生成一個(gè)新的文件,發(fā)布的時(shí)候真是在文件堆里找?。?/p>
這一系列的問(wèn)題如山倒,組內(nèi)的開(kāi)發(fā)同學(xué)已經(jīng)沒(méi)法愉快的開(kāi)發(fā)了。
3.3 深度優(yōu)化
減少?zèng)_突問(wèn)題
進(jìn)一步解決的方案還是細(xì)分模塊,測(cè)試環(huán)境不進(jìn)行文件合并,這樣沖突的概率幾乎很小,因?yàn)楣矌?kù)經(jīng)過(guò)2.0的調(diào)整已經(jīng)基本穩(wěn)定。
縮短時(shí)間
構(gòu)建時(shí)間這么長(zhǎng),這樣發(fā)展下去是不行的。花了一些時(shí)間研究FIS源碼,發(fā)現(xiàn)FIS監(jiān)聽(tīng)的是整個(gè)項(xiàng)目文件,每一次構(gòu)建都要掃描全部文件,這樣時(shí)間必然會(huì)隨著文件增加而變長(zhǎng)。然后進(jìn)行深度改造,變得不那么像FIS了。 進(jìn)行一次又一次優(yōu)化,改變構(gòu)建策略。
依賴構(gòu)建:當(dāng)某個(gè)文件依賴另一個(gè)文件時(shí),另一個(gè)文件才會(huì)被構(gòu)建。假如a.html依賴了b.js ,在構(gòu)建產(chǎn)出的文件就只有這兩個(gè)文件,其他文件不會(huì)被構(gòu)建,文件數(shù)也減少,時(shí)間大大縮短。
開(kāi)發(fā)構(gòu)建(單位ms )
發(fā)布構(gòu)建(單位ms)
構(gòu)建命令優(yōu)化
輸入命令麻煩,就用GUI界面,點(diǎn)點(diǎn)按鈕就行。這里要感謝@koppthe@kolawang同學(xué)短時(shí)間內(nèi)用node寫(xiě)的GUI。
產(chǎn)出文件多
依賴構(gòu)建之后,只會(huì)產(chǎn)出相關(guān)文件,產(chǎn)出文件大大減少,發(fā)布難度減少很多。
ARS流程
修復(fù)bug的時(shí)候不用ARS同步,監(jiān)聽(tīng)文件變化直接同步到測(cè)試環(huán)境。
只需要8ms?。。 ?如果打開(kāi)了同步按鈕,修改的文件會(huì)立馬上傳到測(cè)試環(huán)境上,會(huì)不會(huì)有相互覆蓋的問(wèn)題。組內(nèi)每個(gè)人負(fù)責(zé)的模塊都不同,而且公共模塊已經(jīng)基本穩(wěn)定,很難出現(xiàn)這樣 的問(wèn)題,在實(shí)踐中很少發(fā)生這樣的事情,相反小伙伴覺(jué)得簡(jiǎn)直獲得解脫,相比找文件傳文件這樣繁瑣的流程,這輕松了許多。
發(fā)布優(yōu)化
構(gòu)建工具會(huì)產(chǎn)出文件列表,點(diǎn)擊就能打開(kāi)文件夾,找到對(duì)應(yīng)文件;列表對(duì)應(yīng)SVN路徑,直接貼到ARS就能提單。
雪碧圖的優(yōu)化
發(fā)布的時(shí)候所有引用的CSS文件會(huì)合并成一個(gè),然后將引用的圖標(biāo)合并為雪碧圖,有點(diǎn)粗暴。因?yàn)楣驳腃SS文件的圖片單獨(dú)合并為雪碧圖會(huì)更加合理,公共的圖片變動(dòng)頻率不會(huì)那么高。開(kāi)發(fā)一插件,在CSS合并前雪碧圖一次,合并后再雪碧圖一次。
統(tǒng)計(jì)與優(yōu)化
用戶網(wǎng)絡(luò)類型(粗略)
unknown是無(wú)法統(tǒng)計(jì)到的,理論上wifi還是占大部分。從其他四種類型看,wifi占據(jù)絕大部分,2g用戶非常少。
PC VS Mobile
在JS下載和執(zhí)行效率上,移動(dòng)端明顯要低于PC端。
JS優(yōu)化
之前APP內(nèi)部的JS文件都是通過(guò)seajs來(lái)下載文件,后來(lái)發(fā)覺(jué)何不直接干脆點(diǎn)直接寫(xiě)<script>下載就好了,優(yōu)化后下載執(zhí)行時(shí)間下降顯著:
注:這里統(tǒng)計(jì)的時(shí)間,包括了下載JS和執(zhí)行JS的時(shí)間。
JS內(nèi)嵌與外聯(lián)對(duì)比
在 考慮優(yōu)化的時(shí)候,我們一種方案便是將外聯(lián)的JS代碼(僅業(yè)務(wù)代碼)通過(guò)工具內(nèi)嵌到頁(yè)面?,F(xiàn)在來(lái)對(duì)比下性能:
http://gqq.gtimg.com/static/mobile/js/v3/page/gift/list /inappand.a9a524eb.lc.js文件大小8.7kb,gzip壓縮后3.3kb。
內(nèi)聯(lián)加載時(shí)間幾乎為0 0.0015793,外聯(lián)的下載時(shí)間:
下載時(shí)間不到200ms,但相對(duì)來(lái)說(shuō)已經(jīng)是很長(zhǎng)了,才8.7kb。
我們知道,DOMContentLoaded事件的觸發(fā)基本意味著頁(yè)面已經(jīng)渲染完成,JS已經(jīng)執(zhí)行(異步的除外),已經(jīng)達(dá)到可交互的狀態(tài)了。下面看下內(nèi)聯(lián)與外聯(lián)對(duì)DOMContentLoaded的影響:
藍(lán) 色線條是外聯(lián)的JS,時(shí)間明顯要比內(nèi)聯(lián)的高出一些,大概200ms。由此可見(jiàn),將小量的JS文件內(nèi)聯(lián)到頁(yè)面,能夠提高速度。但大的JS文件適不適合內(nèi)聯(lián), 目前還沒(méi)有實(shí)驗(yàn)。這里需要在減少HTTP請(qǐng)求和利用緩存之間把握一個(gè)平衡,很多時(shí)候優(yōu)化準(zhǔn)則是并不是那么容易實(shí)施,因?yàn)榭赡茏韵嗝埽部赡芎凸こ瘫旧硐?矛盾。優(yōu)化不是按照準(zhǔn)則照本宣科的做,需要靈活變通。
優(yōu)化措施
按照雅虎優(yōu)化的14條準(zhǔn)則,把還沒(méi)做到的都處理了。
- 腳本域名切換,去cookie。
- 文件合并
- 利用瀏覽器緩存,無(wú)限增大緩存期max-age=15552000
- 雪碧圖
- 減少HTTP請(qǐng)求,構(gòu)建工具內(nèi)嵌JS到HTML
- 感覺(jué)速度還是不夠快,再充分利用本地緩存和APP提供的緩存能力
- 瀏覽器使用localstorage緩存腳本
- APP緩存hash文件名腳本
- 緩存HTML片段
調(diào)試、測(cè)試、體驗(yàn)流程
反向代理+白名單控制策略,域名對(duì)外訪問(wèn)是403,公司內(nèi)網(wǎng)可訪問(wèn)。不用代理,手機(jī)直接連接wifi訪問(wèn)。環(huán)境分為開(kāi)發(fā)——測(cè)試——預(yù)發(fā)布——正式(每個(gè)環(huán)境對(duì)應(yīng)一個(gè)獨(dú)立域名),任何角色(開(kāi)發(fā)、測(cè)試、設(shè)計(jì)、產(chǎn)品)都可隨時(shí)訪問(wèn)。
APP的debug包,可任意切換上面四種環(huán)境進(jìn)行調(diào)試、測(cè)試、體驗(yàn)。
總結(jié)
這是過(guò)去一年工作的總結(jié),一直都沒(méi)靜下來(lái)梳理?;剡^(guò)頭想,自己是不是把這個(gè)流程變得更加復(fù)雜了??赡芏加幸粋€(gè)從簡(jiǎn)單到復(fù)雜再到簡(jiǎn)單的過(guò)程,堅(jiān)持優(yōu)化一直沒(méi)有停下來(lái),只要能夠變得更好一點(diǎn)點(diǎn),都會(huì)去嘗試,所謂生命不息,折騰不止。
文章轉(zhuǎn)載請(qǐng)保留網(wǎng)址:http://waterplane.cn/news/industry/1525.html