1 優化css
1.1 避免使用CSS表示式
用CSS表示式動態設定CSS屬性,是一種強大又危險的方式。從IE5開始支援,但從IE8起就不推薦使用了。例如,可以用CSS表示式把背景顏色設定成按小時交替的
- 儘量減少標籤選擇器的使用
- 儘可能少使用id選擇器,多使用樣式選擇器(通用性強)
- 減少選擇器字首,例如.headerBox .nav .left a{} 選擇器是從右向左查詢的
- 避免使用css表示式
background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );
複製程式碼
1.2 減少頁面中的冗餘程式碼
儘可能提高方法的重複使用率:“低耦合高內聚”
1.3 選擇捨棄@import
前面提到了一個最佳實踐:為了實現逐步渲染,CSS應該放在頂部。 在IE中用
@import
與在底部用<link>
效果一樣,所以最好不要用它。
1.4 避免使用濾鏡
IE專有的AlphaImageLoader
濾鏡可以用來修復IE7之前的版本中半透明PNG圖片的問題。在圖片載入過程中,這個濾鏡會阻塞渲染,卡住瀏覽器,還會增加記憶體消耗而且是被應用到每個元素的,而不是每個圖片,所以會存在一大堆問題。
最好的方法是乾脆不要用AlphaImageLoader
,而優雅地降級到用在IE中支援性很好的PNG8圖片來代替。如果非要用AlphaImageLoader
,應該用下劃線hack:_filter
來避免影響IE7及更高版本的使用者。
1.5 把樣式表放在頂部
把樣式表放到文件的HEAD部分能讓頁面看起來載入地更快。這是因為把樣式表放在head裡能讓頁面逐步渲染。
關注效能的前端工程師想讓頁面逐步渲染。也就是說,我們想讓瀏覽器儘快顯示已有內容,這在頁面上有一大堆內容或者使用者網速很慢時顯得尤為重要。給使用者顯示反饋(比如進度指標)的重要性已經被廣泛研究過,並且被記錄下來了。在我們的例子中,HTML頁面就是進度指標!當瀏覽器逐漸載入頁面頭部,導航條,頂部logo等等內容的時候,這些都被正在等待頁面載入的使用者當作反饋,能夠提高整體使用者體驗。
1.6 壓縮 css
- 使用線上網站進行壓縮
- 使用html-minifier 對html 中的css 進行壓縮
- 使用clean-css 對css進行壓縮
- webpack,gulp打包工具
2 優化圖片
2.1 圖片格式
嘗試把GIF格式轉換成PNG格式,看看是否節省空間。在所有的PNG圖片上執行pngcrush(或者其它PNG優化工具)
2.2 優化CSS Sprite
採用css雪碧圖(css sprit/css 圖片精靈)技術,吧一些小圖合併在一張大圖上面,使用的時候,通過北京圖片定位,定位到具體的某一張小圖上
- 在Sprite圖片中橫向排列一般都比縱向排列的最終檔案小
- 組合Sprite圖片中的相似顏色可以保持低色數,最理想的是256色以下PNG8格式
- “對移動端友好”,不要在Sprite圖片中留下太大的空隙。雖然不會在很大程度上影響圖片檔案的大小,但這樣做可以節省使用者代理把圖片解壓成畫素對映時消耗的記憶體。100×100的圖片是1萬個畫素,而1000×1000的圖片就是100萬個畫素了。
.pubBg{
background:url('../img/sprit.png') no-repeat;
background-size:x y; // 和原圖的大小保持一致
}
.box{
background-position:x y; // 通過背景定位,定位到具體的位置,展示不同的圖片極客
}
複製程式碼
頁面中沒法送一次http請求,都需要完成請求+響應這個完整的http事務,會消耗一些時間,也可能會導致http連結通道的堵塞,為了提高頁面的載入速度和執行的效能,我們應該減少http的請求次數和減少請求內容的大小。
2.3 影像對映
可以把多張圖片合併成單張圖片,總大小是一樣的,但減少了請求數並加速了頁面載入。圖片對映只有在影像在頁面中連續的時候才有用,比如導航條。給image map設定座標的過程既無聊又容易出錯,用image map來做導航也不容易,所以不推薦用這種方式。
2.4 行內圖片(Base64編碼)
用data: URL模式來把圖片嵌入頁面。這樣會增加HTML檔案的大小,把行內圖片放在(快取的)樣式表中是個好辦法,而且成功避免了頁面變“重”。但目前主流瀏覽器並不能很好地支援行內圖片。
減少頁面的HTTP請求數是個起點,這是提升站點首次訪問速度的重要指導原則。
2.5 不要用HTML縮放圖片
不要因為在HTML中可以設定寬高而使用本不需要的大圖。如果需要
<img width="100" height="100" src="mycat.jpg" alt="My Cat" />
複製程式碼
那麼圖片本身(mycat.jpg)應該是100x100px的,而不是去縮小500x500px的圖片。
2.6 用小的可快取的favicon.ico(P.S. 收藏夾圖示)
favicon.ico是放在伺服器根目錄的圖片,它會帶來一堆麻煩,因為即便你不管它,瀏覽器也會自動請求它,所以最好不要給一個404 Not Found響應。而且只要在同一個伺服器上,每次請求它時都會傳送cookie,此外這個圖片還會干擾下載順序,例如在IE中,當你在onload中請求額外元件時,將會先下載favicon。
所以為了緩解favicon.ico的缺點,應該確保:
- 足夠小,最好在1K以下
- 設定合適的有效期HTTP頭(以後如果想換的話就不能重新命名了),把有效期設定為幾個月後一般比較安全,可以通過檢查當前favicon.ico的最後修改日期來確保變更能讓瀏覽器知道。
2.7 壓縮image
- 使用雪花圖
- 使用雪花圖 www.spritecow.com/
- 使用雪花圖 www.spritecow.com/
- 使用向量圖
- 使用向量圖字型 fontawesome.dashgame.com/
- 使用阿里向量相簿 www.iconfont.cn/
- 使用向量圖轉成字型 icomoon.io/
- 使用向量圖字型 fontawesome.dashgame.com/
- 使用base64轉換
- 使用網站壓縮
- 使用無失真壓縮 tinypng.com/
- png轉換webp zhitu.isux.us/
- 使用無失真壓縮 tinypng.com/
- 合理使用格式圖片
- jpg有失真壓縮,壓縮率搞,不支援透明
- png支援透明,瀏覽器相容好
- webp壓縮程度更好,在ios webview有相容性問題
- svg向量圖,程式碼內嵌,相對於較小,圖片樣式相對簡單的場景
- jpg有失真壓縮,壓縮率搞,不支援透明
在使用webp的過程中,會產生一些瀏覽器相容問題
function checkWebp() {
try{
return (document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0);
}catch(err) {
return false;
}
}
$(document).ready(function() {
var webp_good = checkWebp();
if(webp_good == false) {
$('img').each(function() {
var src = $(this).attr('src');
if(typeof src != 'undefined') {
src = src.replace('/format,webp', '/format,jpg'); //將webp格式轉換成jpg格式
$(this).attr('src', src);
}
var original = $(this).attr('original'); //針對用了懶載入的情況
if(typeof original != 'undefined') {
original = original.replace('/format,webp', '/format,jpg'); //將webp格式轉換成jpg格式
$(this).attr('original', original);
}
})
}
})
複製程式碼
2.8 圖片懶載入
採用圖片懶載入技術,在頁面開始載入時候,不請求真實的圖片地址,而是預設圖佔位,當頁面載入完成後,在根據相關的條件依次載入真實的圖片(減少頁面首次載入http請求的次數)
真實專案中,我們開始圖片都不載入,頁面首次載入完成,先把第一螢幕中看見的圖片進行載入,隨著頁面的滾動,在下面區域中能夠呈現出來的圖片進行載入
- 根據圖片懶載入技術,我們還可以擴充出,資料懶載入
開始載入頁面的時候,我們只把首屏或者前兩屏的資料從伺服器進行請求(有些網站首屏資料是後臺渲染好,整體返回給客戶端呈現的)
- 當頁面下拉,滾動到哪個區域,在把這個區域需要的資料進行請求(請求回來資料繫結以及圖片延遲載入等)
- 分頁展示技術採用的也是資料懶載入思想實現的:如果我們開始請求獲取的資料是很多的資料,我們最好分批請求,開始只請求第一頁的資料,當頁面點選第二頁(微博是下拉到一定距離後,再請求第二頁資料)的時候請求第二頁資料。
3 優化js
3.1 去除重複指令碼
頁面含有重複的指令碼檔案會影響效能,這可能和你想象的不一樣。在對美國前10大web站點的評審中,發現只有2個站點含有重複指令碼。兩個主要原因增加了在單一頁面中出現重複指令碼的機率:團隊大小和指令碼數量。在這種情況下,重複指令碼會建立不必要的HTTP請求,執行無用的JavaScript程式碼,而影響頁面效能。
IE會產生不必要的HTTP請求,而Firefox不會。在IE中,如果一個不可快取的外部指令碼被頁面引入了兩次,它會在頁面載入時產生兩個HTTP請求。即使指令碼是可快取的,在使用者重新載入頁面時也會產生額外的HTTP請求。
除了產生沒有意義的HTTP請求之外,多次對指令碼求值也會浪費時間。因為無論指令碼是否可快取,在Firefox和IE中都會執行冗餘的JavaScript程式碼。
避免不小心把相同指令碼引入兩次的一種方法就是在模版系統中實現指令碼管理模組。典型的指令碼引入方法就是在HTML頁面中用SCRIPT標籤:
<script type="text/javascript" src="menu_1.0.17.js"></script>
複製程式碼
3.2 儘量減少DOM訪問
一個複雜的頁面意味著要下載更多的位元組,而且用JavaScript訪問DOM也會更慢。舉個例子,想要新增一個事件處理器的時候,迴圈遍歷頁面上的500個DOM元素和5000個DOM元素是有區別的。
操作dom的弊端
- dom存在對映在機制(js中的dom元素物件和頁面中dom結構是存在對映機制的,一改則都改),這種對映機制,是瀏覽器安卓w3c標準完成對js語言的構建和dom的構建(其實就是構建一個監聽機制),操作dom是同事修改兩個地址,相對於一些其他的js程式設計來說消耗效能的。
- 頁面中的dom結構改變或者樣式改變,會觸發瀏覽器的迴流(瀏覽器會把dom結構重新進行計算,這個操作很耗效能)和重繪(吧一個元素的樣式重新渲染)
在做dom事件繫結的時候,儘量避免一個個的事件繫結,二採用效能更高的事件委託來實現
事件委託(事件代理) 把時間板頂給外層容器,當裡面的後代元素相關行為被處罰,外層容器繫結的方法也會被觸發執行(冒泡傳播機制導致),通過的事件源是誰,我們做不同的操作即可
用JavaScript訪問DOM元素是很慢的,所以,為了讓頁面反應更迅速,應該:
- 快取已訪問過的元素的索引
- 先“離線”更新節點,再把它們添到DOM樹上
- 避免用JavaScript修復佈局問題
DOM元素的數量很容易測試,只需要在控制檯裡輸入
document.getElementsByTagName('*').length
複製程式碼
3.3 用智慧的事件處理器
有時候感覺頁面反映不夠靈敏,是因為有太多頻繁執行的事件處理器被新增到了DOM樹的不同元素上,這就是推薦使用事件委託的原因。如果一個div
裡面有10個按鈕,應該只給div容器新增一個事件處理器,而不是給每個按鈕都新增一個。事件能夠冒泡,所以可以捕獲事件並得知哪個按鈕是事件源。
3.4 更多非同步操作編譯
- 同步程式設計會導致:上面東西完不成,下面任務也做不了,我們開發的時候,可以把某一個區域模組都設定為非同步程式設計,這樣只要模組之間沒有必然的先後順序,都可以獨立進行載入,不會受到上面模組的堵塞影響(用的不多)
- 尤其是ajax資料請求,我們一般都要使用非同步程式設計,最好是基於promise設計模式進行管理(專案中經常使用fetch、vue、axios)等外掛進行ajax請求處理,因為這些外掛中就是基於promise設計模式對ajax進行了封裝處理
- 在真實的專案中,我們儘可能避免一次性迴圈過多資料(因為迴圈操作是同步程式設計),尤其是要避免while導致的死迴圈操作
3.5 JS中避免使用eval
- 效能消耗大
- 程式碼壓縮後,容易出現程式碼執行錯亂問題
3.6 JS中儘量減少閉包的使用
- 閉包會形成一個不銷燬的棧記憶體,過多的棧記憶體累積影響頁面的效能
- 還會容易導致記憶體的洩露
- 閉包也有自己的優勢:儲存和保護,我們只能儘量減少,但是無法避免
3.7 儘量使用css3動替代js動畫
css3的動畫或者變形都開啟了硬體加速,效能比js動畫好
3.8 快取做處理
對於不經常更新的資料,最好採用瀏覽器的304快取做處理
例如:
第一次請求css和js下拉,瀏覽器會把請求的內容快取起來,如果做了304處理,使用者再次請求css和js直接從快取中讀取,不需要再去伺服器獲取了(減少了http請求次數)
當使用者強制重新整理頁面(ctrl+f5)或者當前快取的css或者js發生了變動,都會從新從伺服器端拉取
對於客戶端來講,我們還可以基於localStronge來做一些本地儲存,例如:第一次請求的資料或者不經常更新的css和js,我們都可以吧內容儲存在本地,下一次頁面載入,我們從本地中獲取即可,我們設定一定的期限或者一些標識,可以控制在某個階段重新從伺服器獲取
3.9 設計模式
編寫js程式碼的時候儘可能使用設計模式來構建體系,方便後期的維護,也提高了擴充性等
3.10 把指令碼放在底部
指令碼會阻塞並行下載,HTTP/1.1官方文件建議瀏覽器每個主機名下並行下載的元件數不要超過兩個,如果圖片來自多個主機名,並行下載的數量就可以超過兩個。如果指令碼正在下載,瀏覽器就不開始任何其它下載任務,即使是在不同主機名下的。
有時候,並不容易把指令碼移動到底部。舉個例子,如果指令碼是用document.write
插入到頁面內容中的,就沒辦法再往下移了。還可能存在作用域問題,在多數情況下,這些問題都是可以解決的。
一個常見的建議是用推遲(deferred)指令碼,有DEFER
屬性的指令碼意味著不能含有document.write,並且提示瀏覽器告訴他們可以繼續渲染。不幸的是,Firefox不支援DEFER
屬性。在IE中,指令碼可能被推遲,但不盡如人意。如果指令碼可以推遲,我們就可以把它放到頁面底部,頁面就可以更快地載入。
3.11 壓縮js
- 使用線上網站進行壓縮
- 使用html-minifier 對html 中的css 進行壓縮
- 使用uglifjs2對js進行壓縮
- webpack,gulp打包工具
4 優化html
4.1 audio或者video標籤
如果當頁面中出現audio或者video標籤,我們最好設定它們的preload=:頁面載入的時候,音視訊資源不進行載入,播放的時候再開始載入(減少頁面首次載入http請求的次數)
- preload=auto 頁面首次載入的時候就把音訊資源進行載入
- preload=metadata 頁面首次載入的時候只能音視資源的頭部資訊進行載入
4.2 儘量少用iframe
用iframe可以把一個HTML文件插入到父文件裡,重要的是明白iframe是如何工作的並高效地使用它。<iframe>
的優點:
- 引入緩慢的第三方內容,比如標誌和廣告
- 安全沙箱
- 並行下載指令碼
<iframe>
的缺點:
- 代價高昂,即使是空白的iframe
- 阻塞頁面載入
- 非語義
4.3 杜絕404
HTTP請求代價高昂,完全沒有必要用一個HTTP請求去獲取一個無用的響應(比如404 Not Found),只會拖慢使用者體驗而沒有任何好處。
有些站點用的是有幫助的404——“你的意思是xxx?”,這樣做有利於使用者體驗,,但也浪費了伺服器資源(比如資料庫等等)。最糟糕的是連結到的外部JavaScript有錯誤而且結果是404。首先,這種下載將阻塞並行下載。其次,瀏覽器會試圖解析404響應體,因為它是JavaScript程式碼,需要找出其中可用的部分。
5 移動端
5.1 保證所有元件都小於25K
這個限制是因為iPhone不能快取大於25K的元件,注意這裡指的是未壓縮的大小。這就是為什麼縮減內容本身也很重要,因為單純的gzip可能不夠。
5.2 把元件打包到一個複合文件裡
把各個元件打包成一個像有附件的電子郵件一樣的複合文件裡,可以用一個HTTP請求獲取多個元件(記住一點:HTTP請求是代價高昂的)。用這種方式的時候,要先檢查使用者代理是否支援(iPhone就不支援)。
6 cookie
6.1 給Cookie減肥
使用cookie的原因有很多,比如授權和個性化。HTTP頭中cookie資訊在web伺服器和瀏覽器之間交換。重要的是保證cookie儘可能的小,以最小化對使用者響應時間的影響。
- 清除不必要的cookie
- 保證cookie儘可能小,以最小化對使用者響應時間的影響
- 注意給cookie設定合適的域級別,以免影響其它子域
- 設定合適的有效期,更早的有效期或者none可以更快的刪除cookie,提高使用者響應時間
6.2 把元件放在不含cookie的域下
當瀏覽器傳送對靜態影像的請求時,cookie也會一起傳送,而伺服器根本不需要這些cookie。所以它們只會造成沒有意義的網路通訊量,應該確保對靜態元件的請求不含cookie。可以建立一個子域,把所有的靜態元件都部署在那兒。
如果域名是www.example.org,可以把靜態元件部署到static.example.org。然而,如果已經在頂級域example.org或者www.example.org設定了cookie,那麼所有對static.example.org的請求都會含有這些cookie。這時候可以再買一個新域名,把所有的靜態元件部署上去,並保持這個新域名不含cookie。Yahoo!用的是yimg.com,YouTube是ytimg.com,Amazon是images-amazon.com等等。
把靜態元件部署在不含cookie的域下還有一個好處是有些代理可能會拒絕快取帶cookie的元件。有一點需要注意:如果不知道應該用example.org還是www.example.org作為主頁,可以考慮一下cookie的影響。省略www的話,就只能把cookie寫到*.example.org,所以因為效能原因最好用www子域,並且把cookie寫到這個子域下。
7 伺服器
7.1 Gzip元件
前端工程師可以想辦法明顯地縮短通過網路傳輸HTTP請求和響應的時間。毫無疑問,終端使用者的頻寬速度,網路服務商,對等交換點的距離等等,都是開發團隊所無法控制的。但還有別的能夠影響響應時間的因素,壓縮可以通過減少HTTP響應的大小來縮短響應時間。
從HTTP/1.1開始,web客戶端就有了支援壓縮的Accept-Encoding HTTP請求頭。
1 | Accept-Encoding: gzip, deflate |
---|
如果web伺服器看到這個請求頭,它就會用客戶端列出的一種方式來壓縮響應。web伺服器通過Content-Encoding相應頭來通知客戶端。
1 | Content-Encoding: gzip |
---|
儘可能多地用gzip壓縮能夠給頁面減肥,這也是提升使用者體驗最簡單的方法。
7.2 避免圖片src屬性為空
Image with empty string src屬性是空字串的圖片很常見,主要以兩種形式出現:
-
straight HTML
-
JavaScript
-
var img = new Image(); img.src = “”;
這兩種形式都會引起相同的問題:瀏覽器會向伺服器傳送另一個請求。
7.3 配置ETags
實體標籤(ETags),是伺服器和瀏覽器用來決定瀏覽器快取中元件與源伺服器中的元件是否匹配的一種機制(“實體”也就是元件:圖片,指令碼,樣式表等等)。新增ETags可以提供一種實體驗證機制,比最後修改日期更加靈活。一個ETag是一個字串,作為一個元件某一具體版本的唯一識別符號。唯一的格式約束是字串必須用引號括起來,源伺服器用相應頭中的ETag
來指定元件的ETag:
1 2 3 4 |
HTTP/1.1 200 OK ``Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT ``ETag: "10c24bc-4ab-457e1c1f" ``Content-Length: 12195 |
---|
然後,如果瀏覽器必須驗證一個元件,它用If-None-Match
請求頭來把ETag傳回源伺服器。如果ETags匹配成功,會返回一個304狀態碼,這樣就減少了12195個位元組的響應體。
GET /i/yahoo.gif HTTP/1.1
Host: us.yimg.com
If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
If-None-Match: "10c24bc-4ab-457e1c1f"
HTTP/1.1 304 Not Modified
** **
7.4 對Ajax用GET請求
郵箱團隊發現使用XMLHttpRequest
時,瀏覽器的POST請求是通過一個兩步的過程來實現的:先傳送HTTP頭,在傳送資料。所以最好用GET請求,它只需要傳送一個TCP報文(除非cookie特別多)。IE的URL長度最大值是2K,所以如果要傳送的資料超過2K就無法使用GET了。
POST請求的一個有趣的副作用是實際上沒有傳送任何資料,就像GET請求一樣。正如HTTP說明文件中描述的,GET請求是用來檢索資訊的。所以它的語義只是用GET請求來請求資料,而不是用來傳送需要儲存到伺服器的資料。
7.5 儘早清空緩衝區
當使用者請求一個頁面時,伺服器需要用大約200到500毫秒來組裝HTML頁面,在這期間,瀏覽器閒等著資料到達。PHP中有一個flush()函式,允許給瀏覽器傳送一部分已經準備完畢的HTML響應,以便瀏覽器可以在後臺準備剩餘部分的同時開始獲取元件,好處主要體現在很忙的後臺或者很“輕”的前端頁面上(P.S. 也就是說,響應時耗主要在後臺方面時最能體現優勢)。
較理想的清空緩衝區的位置是HEAD後面,因為HTML的HEAD部分通常更容易生成,並且允許引入任何CSS和JavaScript檔案,這樣就可以讓瀏覽器在後臺還在處理的時候就開始並行獲取元件。
例如:
 <br />... <!-- css, js --><br /> </head><br /> <?php flush(); ?><br /> <body><br /> ... <!-- content --><br />
複製程式碼
7.6 使用CDN(內容分發網路)
使用者與伺服器的物理距離對響應時間也有影響。把內容部署在多個地理位置分散的伺服器上能讓使用者更快地載入頁面。但具體要怎麼做呢?
實現內容在地理位置上分散的第一步是:不要嘗試去重新設計你的web應用程式來適應分散式結構。這取決於應用程式,改變結構可能包括一些讓人望而生畏的任務,比如同步會話狀態和跨伺服器複製資料庫事務(翻譯可能不準確)。縮短使用者和內容之間距離的提議可能被推遲,或者根本不可能通過,就是因為這個難題。
記住終端使用者80%到90%的響應時間都花在下載頁面元件上了:圖片,樣式,指令碼,Flash等等,這是業績黃金法則。最好先分散靜態內容,而不是一開始就重新設計應用程式結構。這不僅能夠大大減少響應時間,還更容易表現出CDN的功勞。
內容分發網路(CDN)是一組分散在不同地理位置的web伺服器,用來給使用者更高效地傳送內容。典型地,選擇用來傳送內容的伺服器是基於網路距離的衡量標準的。例如:選跳數(hop)最少的或者響應時間最快的伺服器。
7.7 添上Expires或者Cache-Control HTTP頭
這條規則有兩個方面:
- 對於靜態元件:通過設定一個遙遠的將來時間作為
Expires
來實現永不失效 - 多餘動態元件:用合適的
Cache-Control
HTTP頭來讓瀏覽器進行條件性的請求
網頁設計越來越豐富,這意味著頁面裡有更多的指令碼,圖片和Flash。站點的新訪客可能還是不得不提交幾個HTTP請求,但通過使用有效期能讓元件變得可快取,這避免了在接下來的瀏覽過程中不必要的HTTP請求。有效期HTTP頭通常被用在圖片上,但它們應該用在所有元件上,包括指令碼、樣式和Flash元件。
瀏覽器(和代理)用快取來減少HTTP請求的數目和大小,讓頁面能夠更快載入。web伺服器通過有效期HTTP響應頭來告訴客戶端,頁面的各個元件應該被快取多久。用一個遙遠的將來時間做有效期,告訴瀏覽器這個響應在2010年4月15日前不會改變。
1 | Expires: Thu, 15 Apr 2010 20:00:00 GMT |
---|
如果你用的是Apache伺服器,用ExpiresDefault指令來設定相對於當前日期的有效期。下面的例子設定了從請求時間起10年的有效期:
ExpiresDefault "access plus 10 years"
7.8 減少dns查詢
域名系統建立了主機名和IP地址間的對映,就像電話簿上人名和號碼的對映一樣。當你在瀏覽器輸入www.shanghai70.com的時候,瀏覽器就會聯絡DNS解析器返回伺服器的IP地址。DNS是有成本的,它需要20到120毫秒去查詢給定主機名的IP地址。在DNS查詢完成之前,瀏覽器無法從主機名下載任何東西。
DNS查詢被快取起來更高效,由使用者的ISP(網路服務提供商)或者本地網路存在一個特殊的快取伺服器上,但還可以快取在個人使用者的計算機上。DNS資訊被儲存在作業系統的DNS cache(微軟Windows上的”DNS客戶端服務”)裡。大多數瀏覽器有獨立於作業系統的自己的cache。只要瀏覽器在自己的cache裡還保留著這條記錄,它就不會向作業系統查詢DNS。
IE預設快取DNS查詢30分鐘,寫在DnsCacheTimeout
登錄檔設定中。Firefox快取1分鐘,可以用network.dnsCacheExpiration
配置項設定。(Fasterfox把快取時間改成了1小時 P.S. Fasterfox是FF的一個提速外掛)
如果客戶端的DNS cache是空的(包括瀏覽器的和作業系統的),DNS查詢數等於頁面上不同的主機名數,包括頁面URL,圖片,指令碼檔案,樣式表,Flash物件等等元件中的主機名,減少不同的主機名就可以減少DNS查詢。
減少不同主機名的數量同時也減少了頁面能夠並行下載的元件數量,避免DNS查詢削減了響應時間,而減少並行下載數量卻增加了響應時間。我的原則是把元件分散在2到4個主機名下,這是同時減少DNS查詢和允許高併發下載的折中方案。
7.9 避免重定向
重定向用301和302狀態碼,下面是一個有301狀態碼的HTTP頭
HTTP/1.1 301 Moved Permanently Location: example.com/newuri Content-Type: text/html
瀏覽器會自動跳轉到Location
域指明的URL。重定向需要的所有資訊都在HTTP頭部,而響應體一般是空的。其實額外的HTTP頭,比如Expires
和Cache-Control
也表示重定向。除此之外還有別的跳轉方式:refresh元標籤和JavaScript,但如果你必須得做重定向,最好用標準的3xxHTTP狀態碼,主要是為了讓返回按鈕能正常使用。
牢記重定向會拖慢使用者體驗,在使用者和HTML文件之間插入重定向會延遲頁面上的所有東西,頁面無法渲染,元件也無法開始下載,直到HTML文件被送達瀏覽器。
有一種常見的極其浪費資源的重定向,而且web開發人員一般都意識不到這一點,就是URL尾部缺少一個斜線的時候。例如,跳轉到www.shanghai70.com/a會返回一個重定向到www.shanghai70.com/b的301響應(注意添在尾部的斜線)。在Apache中可以用Alias
,mod_rewrite
或者DirectorySlash
指令來取消不必要的重定向。
重定向最常見的用途是把舊站點連線到新的站點,還可以連線同一站點的不同部分,針對使用者的不同情況(瀏覽器型別,使用者帳號型別等等)做一些處理。用重定向來連線兩個網站是最簡單的,只需要少量的額外程式碼。雖然在這些時候使用重定向減少了開發人員的開發複雜度,但降低了使用者體驗。一種替代方案是用Alias
和mod_rewrite
,前提是兩個程式碼路徑都在相同的伺服器上。如果是因為域名變化而使用了重定向,就可以建立一條CNAME(建立一個指向另一個域名的DNS記錄作為別名)結合Alias
或者mod_rewrite
指令。
7.10 Json格式傳輸
在客戶端和伺服器端進行資料通訊的時候,我們儘量採用json格式進行資料傳輸
- json格式的資料,能夠清晰明瞭的展示出資料結構,而且也方便我們獲取的操作
- 相對於很早以前的xml格式傳輸,json格式的資料更加輕量級
- 客戶端和伺服器端都支援json格式資料的處理,處理起來非常的方便
真實專案中:並不是所有的資料都基於json,我們儘可能這樣做,但是對於某些特殊的需求(例如檔案流的傳輸或者文件傳輸),使用json就不合適了