著第3屆bt論壇的順利結(jié)束的秋風(fēng),我也來分享一下自己在前端優(yōu)化方面的一些些小經(jīng)驗(yàn),其實(shí)這些經(jīng)驗(yàn)本身都是來自yahoo的優(yōu)化原則,不過經(jīng)過ahuaxuan自身的實(shí)踐和再次的思考,把原來的原則都進(jìn)行了分組和分析.不過由于ahuaxuan bt涉及到的東西有限,并沒有經(jīng)歷過全部的優(yōu)化點(diǎn),所以只把自己做過的拿出來和大家討論討論,其中不免加入自己一些觀點(diǎn),希望大家指正.
先說說目標(biāo),前端優(yōu)化的目標(biāo)是什么,一個(gè)字:快.兩個(gè)字:更快.那么下面我們來看看慢的網(wǎng)頁(yè)將會(huì)給我們帶來什么:
1. 慢的頁(yè)面可能會(huì)網(wǎng)站失去更多的用戶.
2. 慢500ms意味著20%的用戶將放棄訪問(google)
3. 慢100ms意味著1%的用戶將放棄交易(amazon)
4. 慢 ???ms意味著??%的用戶將放棄xx(your site)
所以我們的目標(biāo)很明確,就是要網(wǎng)頁(yè)展現(xiàn)的速度更快.
經(jīng)過ahuaxuan的實(shí)踐和總結(jié),其實(shí)要讓網(wǎng)頁(yè)展現(xiàn)更快只需要注意幾個(gè)大的方面,下面會(huì)一一描述這幾個(gè)大的方面.
[size=medium]1減少http請(qǐng)求,我把它排在了第一點(diǎn),為啥要在第一點(diǎn)呢,很簡(jiǎn)單,因?yàn)樗钪匾?
如何做呢.讓ahuaxuan帶著大家分析一下這個(gè)問題.從何處著手呢.ahuaxuan大聲疾呼,我們要從數(shù)據(jù)開始.ok,一般來說,我們從變化性上把數(shù)據(jù)分成兩種類型,變和不變.那么不變的數(shù)據(jù)可以緩存,變化的數(shù)據(jù)不能緩存,這是一個(gè)常識(shí),也就是說要減少我們的http請(qǐng)求次數(shù)這個(gè)目標(biāo)可以轉(zhuǎn)換成把數(shù)據(jù)分為變化和不變化兩個(gè)部分.不變化的數(shù)據(jù)不需要再次請(qǐng)求,這樣http請(qǐng)求的次數(shù)就減少了,下面我們分點(diǎn)來描述將數(shù)據(jù)分類的途徑.
1. 合并腳本文件
包括腳本,樣式和圖片,可以有選擇的把一些Js和css可以合并成一個(gè)文件,一些圖片可以使用css sprites技術(shù).這樣做的原因是什么?做過web開發(fā)的人都知道,js和css基本是不變的,是靜態(tài)文件,圖片亦然.那么不變的文件如果適當(dāng)?shù)暮喜⒃谝黄?會(huì)有什么效果呢?請(qǐng)求的次數(shù)從多次變成了一次.這樣http請(qǐng)求的次數(shù)就減少了.當(dāng)時(shí)合并之后,文件體積變大了,會(huì)影響速度嗎?答:肯定會(huì)啊,不過這里是需要權(quán)衡的,比如我100份靜態(tài)文件,合并成10份還是合并成1份這就得看你得具體情況了.
2. 指定Expires或者Cache-Control,
對(duì)于靜態(tài)內(nèi)容:設(shè)置文件頭過期時(shí)間Expires的值為“Never expire”(永不過期)
動(dòng)態(tài)頁(yè)面,在代碼中添加cache-control,表示多少時(shí)間之后過期,如:
response.setHeader("Cache-Control", "max-age=3600");
如果使用了Expires文件頭,當(dāng)頁(yè)面內(nèi)容改變時(shí)就必須改變內(nèi)容的文件名。通常是在文件內(nèi)容后加版本號(hào)
這一點(diǎn)是大多數(shù)人都忽略得,之前很多人在壇子上發(fā)布自己得小系統(tǒng),還有demo,ahuaxuan跑過去一看,my god,一堆又一堆得js,css,既沒有恰當(dāng)?shù)煤喜?也沒有設(shè)置過期時(shí)間.每次刷新頁(yè)面都要重新下載這一堆又一堆的js,css.http請(qǐng)求那叫一個(gè)多啊.無謂了流量就這樣產(chǎn)生了.
這一點(diǎn)在企業(yè)應(yīng)用的系統(tǒng)中也時(shí)有發(fā)生.比如我們使用extjs作為前端的技術(shù),400多k啊,每打開一個(gè)頁(yè)面都導(dǎo)入,下載這個(gè)js,夠無聊的.那么童子們可能就要問了,靜態(tài)文件為啥不用apache,lighttpd等呢,答,用了又怎么樣,不設(shè)expire或者max-age不是一樣要下載,最好的方法是寫一個(gè)filter,再filter中判斷,如果url滿足一定的條件(比如符合配置文件中的正則表達(dá)式),那么就設(shè)置一個(gè)max-age,這樣就ok,太簡(jiǎn)單了,幾行代碼就可以搞定.快哉.
3. 緩存Ajax請(qǐng)求
緩存的方法同動(dòng)態(tài)頁(yè)面,ajax請(qǐng)求需要使用get方式,url長(zhǎng)度為2k(ie)限制(post請(qǐng)求有兩個(gè)過程,1發(fā)送請(qǐng)求headers,2發(fā)送請(qǐng)求數(shù)據(jù),根據(jù)http規(guī)范,get請(qǐng)求只會(huì)發(fā)送一個(gè)tcp包).--------這一段話來自yahoo,先不管其真假,我們從另外一個(gè)方面來考慮一下為什么最好使用get方式,講一個(gè)ahuaxuan經(jīng)歷過的事情,之前有一個(gè)項(xiàng)目的ajax請(qǐng)求使用了post方式,后來發(fā)現(xiàn)經(jīng)常出錯(cuò),而且拋出了squid的錯(cuò)誤,因?yàn)槲覀兊木W(wǎng)站使用了squid,問題就出在這里了,從http協(xié)議上可以了解到,method=post是指把數(shù)據(jù)提交到服務(wù)器上去,那么squid的一個(gè)特性是不會(huì)緩存post請(qǐng)求(事實(shí)上它確實(shí)不應(yīng)該緩存,因?yàn)檫@樣會(huì)違反http協(xié)議中的語(yǔ)義),把a(bǔ)jax請(qǐng)求改成get方式之后,一切恢復(fù)如常.
4. 移除重復(fù)的js
重復(fù)的js導(dǎo)入也有可能導(dǎo)致ie重新加載該腳本.沒啥好說的,照做.
5. 避免重定向
有一種經(jīng)常被網(wǎng)頁(yè)開發(fā)者忽略卻往往十分浪費(fèi)響應(yīng)時(shí)間的跳轉(zhuǎn)現(xiàn)象。這種現(xiàn)象發(fā)生在當(dāng)URL本該有斜杠(/)卻被忽略掉時(shí)。這時(shí)候會(huì)返回一個(gè)301的狀態(tài)碼,然后瀏覽器重新發(fā)起一次請(qǐng)求.在企業(yè)應(yīng)用里,重定向是我們?cè)谄髽I(yè)應(yīng)用中常用的技術(shù),不過用在網(wǎng)站項(xiàng)目上,您可要小心了,因?yàn)槠胀ǖ闹囟ㄏ蚱鋵?shí)是server在response header中設(shè)置http status=302,瀏覽器收到之后,判斷出是302,會(huì)重新發(fā)送一個(gè)請(qǐng)求,目標(biāo)地址是前一次返回中指定的地址.在網(wǎng)站項(xiàng)目中如果可以不用重定向就別用吧.如果您做企業(yè)應(yīng)用項(xiàng)目,ok,關(guān)系不大,您就放心的”定”吧.
小節(jié),ahuaxuan把減少http請(qǐng)求次數(shù)分為了以上5個(gè)小點(diǎn),每個(gè)小點(diǎn)之后附加一些實(shí)例,大家可以根據(jù)這些點(diǎn)來判斷自己的項(xiàng)目是否可以有優(yōu)化的地方.
使用cdn
讓內(nèi)容更靠近用戶,這有啥好說呢,原理很簡(jiǎn)單,就是根據(jù)用戶瀏覽器所在機(jī)器的ip來判斷哪些服務(wù)器離用戶最近,瀏覽器會(huì)再次去請(qǐng)求這些最近的機(jī)器.一般的cdn服務(wù)商是通過開發(fā)自己的dns server來達(dá)到這個(gè)目的的.不過這個(gè)是通常情況哦,技術(shù)實(shí)力比較高,或者場(chǎng)景比較特殊的公司會(huì)開發(fā)自己的cdn.當(dāng)然不管怎么說,使用cdn肯定可以使頁(yè)面響應(yīng)更快(也包括音頻,視頻,圖片,文本文件,等等等等)
減小返回?cái)?shù)據(jù)的體積
1. 使用gzip壓縮返回?cái)?shù)據(jù)
Gzip壓縮所有可能的文件類型是減少文件體積增加用戶體驗(yàn)的簡(jiǎn)單方法。比如本來400k的文件,壓縮一下之后只有50k-100k,那么網(wǎng)絡(luò)的流量就立刻下來了,壓縮的代價(jià)是服務(wù)器端要壓縮文件,需要消耗cpu,瀏覽器需要解壓文件,也需要消耗cpu,不過對(duì)于現(xiàn)代這么nb的pc,來說,瀏覽器解壓一下數(shù)據(jù)帶來的cpu消耗簡(jiǎn)直不值一提.所以您就壓吧.不過壓的時(shí)候要小心哦,有的瀏覽器在特定場(chǎng)景下會(huì)出去一些小bug,導(dǎo)致頁(yè)面不正常.比如ie6在跨域的時(shí)候可能會(huì)有些小麻煩,把這部分?jǐn)?shù)據(jù)的gzip去掉就可以了.
2. 最小化js文件和css文件
壓縮js可以使用JSMin或者YUI Compressor,后者同時(shí)可以壓縮css,這個(gè)也沒啥好說的,照做吧.
3. 將css和js獨(dú)立成外部文件
其實(shí)這一點(diǎn)也可以看成是區(qū)分不變數(shù)據(jù)和變化數(shù)據(jù).很多人喜歡在頁(yè)面商寫很多很多的js和css,這些數(shù)據(jù)其實(shí)都是不會(huì)變化的數(shù)據(jù),也就是說這些數(shù)據(jù)也是可以緩存在瀏覽器上的,通過把它們獨(dú)立成外部文件,可以把這些數(shù)據(jù)緩存起來.這樣做看上去是增加的請(qǐng)求的次數(shù),但是由于第一次請(qǐng)求之后該部分?jǐn)?shù)據(jù)已經(jīng)被緩存,所以第二次就無需再請(qǐng)求后端,減少了網(wǎng)絡(luò)帶寬的開銷.
優(yōu)化Cookie
1. 減小cookie體積
能不放就別放吧,為啥呀,cookie就象鑰匙串,只有出門和回家得時(shí)候才用,但是一整天你都要帶在身上,麻煩不.
2. 合理設(shè)置Cookie域
由于二級(jí)域名可以拿到一級(jí)域名得cookie,那么如果,而二級(jí)域名之間確不能相互共享cookie,所以合理得設(shè)置cookie得域名也可以避免無必要得帶寬浪費(fèi)和響應(yīng)速度得增加.
3. 設(shè)置合理的cookie過期時(shí)間
該過期就過期,不要讓不必要的數(shù)據(jù)一直帶在身上走來走去.
4. 使用域分離
為圖片或者其他靜態(tài)資源文件使用子域或者建立新的獨(dú)立域名(申請(qǐng)新的域名),避免無必要的cookie傳輸,當(dāng)然也是要在有必要得情況下,圖片類網(wǎng)站肯定有必要,javaeye上得圖片并沒有使用域分離,所以我們得cookie其實(shí)會(huì)帶到壇子得圖片服務(wù)器上去,每次請(qǐng)求圖片都是如此(不過還好,壇子里沒有什么圖片,所以這方面的浪費(fèi)不大).
小結(jié),其實(shí)cookie上得問題,單詞請(qǐng)求看上去也不是什么大問題,好像是無所謂得事情,就那么幾十個(gè)byte,至于嗎,不過大家都聽說過水滴石穿,繩鋸木斷的故事.所以該做的,我們還是要做,正所謂,勿以善小而不為,勿以惡小而為之.
優(yōu)化瀏覽器加載
1. 將css放在頁(yè)面頂部加載
把樣式表放在文檔底部的問題是在包括Internet Explorer在內(nèi)的很多瀏覽器中這會(huì)中止內(nèi)容的有序呈現(xiàn)。瀏覽器中止呈現(xiàn)是為了避免樣式改變引起的頁(yè)面元素重繪。用戶不得不面對(duì)一個(gè)空白頁(yè)面。
HTML規(guī)范清 楚指出樣式表要放包含在頁(yè)面的<head />區(qū)域內(nèi):“和<a />不同,<link />只能出現(xiàn)在文檔的<head />區(qū)域內(nèi),盡管它可以多次使用它”。無論是引起白屏還是出現(xiàn)沒有樣式化的內(nèi)容都不值得去嘗試。最好的方案就是按照HTML規(guī)范在文 檔<head />內(nèi)加載你的樣式表。
2. 將js放在頁(yè)面底部加載
腳本帶來的問題就是它阻止了頁(yè)面的平行下載。HTTP/1.1 規(guī)范建議,瀏覽器每個(gè)主機(jī)名的并行下載內(nèi)容不超過兩個(gè)。如果你的圖片放在多個(gè)主機(jī)名上,你可以在每個(gè)并行下載中同時(shí)下載2個(gè)以上的文件。但是當(dāng)下載腳本時(shí),瀏覽器就不會(huì)同時(shí)下載其它文件了,即便是主機(jī)名不相同。
Js放在底部加載其實(shí)并不影響瀏覽器展示頁(yè)面,除非用戶會(huì)在js加載完成之前就調(diào)用某個(gè)js方法,比如說頁(yè)面剛展現(xiàn)到一半,但是恰好這一半里有一部分是調(diào)用了還未下載的js,這個(gè)時(shí)候就會(huì)出問題了,如果童子們遇到這種情況,可以把這部分js先加載.
總結(jié)一下下:以上這些優(yōu)化點(diǎn)其實(shí)只是前端優(yōu)化的部分內(nèi)容,不過根據(jù)80/20原則,這些優(yōu)化點(diǎn)已經(jīng)覆蓋了80%的情況了,同時(shí)前端優(yōu)化其實(shí)也不是什么復(fù)雜的東西,原理上是很簡(jiǎn)單的,更多的是需要我們的實(shí)踐,因?yàn)槲覀兛赡軙?huì)碰到各種各樣的問題,而很多的這些問題其實(shí)一般是預(yù)測(cè)不到的.只有遇到過才知道.
說的不對(duì)的地方請(qǐng)大家拍磚,或者童子們也可以把自己的經(jīng)驗(yàn)在這里和大家分享一下.代表其他童子表示十分的感謝.
當(dāng)然,由于ahuaxuan水平有限,文章中難免有不到之處,還望不吝指正,謝謝.