之前看到一句話,在這個計算機快速發展的時代里,想要不被計算機代替,就不要像計算機一樣去思考。一直不是很懂這句話是什么道理,直到發現工作到了瓶頸的時候。
作為一個前端工程師,在很多人眼里就是個寫寫頁面的,或者說稍微懂點我們這個行業的人會說:哦,還能跟后端做做交互。但是,工作久了就發現,好像前端的存在感怎么越來越弱了呢。前端這個行業的門檻很低,基本上你只要稍微懂點電腦,花個半個月速成一下,寫幾個前端頁面完全沒有問題。還有就是好多學美工的,他們想要發展,也會學點前端的知識。這樣,好像美工都已經能代替前端了。還記得前幾天我們市場總監問我,你們做前端的除了寫頁面還會干啥,能做美工的嗎。這個問的我一時詞窮,完全不知道該怎么回答...那時候我好想說一句,對不起,我是寫代碼的,不是搞設計的,請尊重我的職業。哈哈,當然這里完全沒有看不上設計的意思,純粹是我對設計並沒有這么好的天賦而已。其次,就是公司的技術總監,完完全全的就是個全棧工程師,因為是創業公司,在我來之前,前后端完全就是他一個人搞定的。這么下來,我發現我純在的必要就更低了,這不是誰都能寫頁面嗎,還要前端干什么。然而,這樣理解對於前端來說太片面跟太局限了。前端怎么可能只是寫寫頁面呢?這是二十年前的前端干的活,實現頁面什么的。現在的前端已經遠遠不是寫個頁面這么簡單了。我們還要考慮頁面如何布局,怎樣給用戶最好的體驗,怎樣讓搜索引擎更容易搜索到我們網站。還有就是現在前端各式各樣的框架,合適框架能大大提升我們網站的性能,而不合適框架卻只能拖慢網站的加載速度。
好了,說了這么多,該說說重點了。我剛剛做前端的時候對前端的理解也很淺,就覺得只要能實現頁面就可以了,所以對網站加載速度什么的並沒有太大的關注。最后網站完成了,發現加載個頁面至少要個七八秒。。。說實在的,這個七八秒可以趕跑絕大部分的用戶了,一般用戶來說,在網站的停留時間頁面兩到三秒,如果在這個時間內網頁不能加載出來的話,用戶基本都會選擇關閉網站。所以說,網站性能優化是很有必要的。在網上看了很多關於性能優化的東西,都是一段一段的,不能系統的學習,后來買了本o'reilly系列的網站性能優化的書,里面寫的非常詳細,這里,我就要說說他其中的一章性能優化之減少HTTP請求。
在我們去訪問一個新的網站的時候,我們在地址欄輸入了一個地址,去請求某個服務器下的文件,然后服務器接收到請求之后,又給我們返回了一個HTML文檔和對應的CSS,JS,img文件,而每一個文件,就是一個HTTP請求。打開我們的開發者工具,點擊Network我們可以看到,在加載一個新的頁面的時候,下載HTML文檔只占下載所有文檔時間的不到20%,大部分都是在10%以下,反而是加載頁面其他文件占據了大部分的加載時間。尤其對於一些多圖片的網站來說,圖片的加載占據的大部分的性能。這里不得不提到網站性能優化書中提到的一條黃金法則:只有10%~20%的用戶的最終響應時間花在了下載HTML文檔上。其余的80%~90%的時間都花在了下載頁面中的所有組件上。這里的組件,指的就是JS,CSS,image這些文件。所以,要提示網站性能,就要減少這些組件,從而減少HTTP請求次數。而在這些組件中,最多的其實就是圖片文件,所以要提示網站性能之一,就是要減少圖片的請求次數。那要怎么減少圖片請求次數呢?
首先,我們可以使用圖片地圖(Image Maps)。圖片地圖,第一次看到這個詞的時候可能會想到是不是跟地圖一樣的圖片,其實不然。圖片地圖其實就是給用戶展示一張圖片,然后用戶點擊這張圖片不同位置的時候,會產生不同的效果。下面就是圖片地圖的使用方法,就是在img標簽中使用一個屬性,uesmap屬性指向map標簽的name屬性。map中的area屬性則是顯示不同的區域的大小,當shape為rect也就是正方形時,coords的前兩個值表示起始位置,后兩個值表示結束位置。
<img usemap="#map1" border=0 src="/images/imagemap.gif?t=1490671322"> <map name="map1"> <area shape="rect" coords="0,0,31,31" href="javascript:alert('Home')" title="Home"> <area shape="rect" coords="36,0,66,31" href="javascript:alert('Gifts')" title="Gifts"> <area shape="rect" coords="71,0,101,31" href="javascript:alert('Cart')" title="Cart"> <area shape="rect" coords="106,0,136,31" href="javascript:alert('Settings')" title="Settings"> <area shape="rect" coords="141,0,171,31" href="javascript:alert('Help')" title="Help"> </map>
我們也可以直接訪問性能優化書提供給我們的體驗地址http://stevesouders.com/examples/imagemap.php。
跟這個相對應的是最普通的每一個按鈕都用不同小圖片的案例的體驗地址http://stevesouders.com/examples/imagemap-no.php。
然后我們把瀏覽器限速開成最大的限速,我用的是google瀏覽器,打開開發者工具,在Network下會有一個No throttling,點擊一下,可以看到最慢的是GPRS,設置了之后,使用了圖片地圖的例子平均加載耗時為2000ms,而沒有使用圖片地圖的例子平均加載耗時為4000ms,這里我們可以看到,使用了圖片地圖的速度提升了進一倍。
不過,雖然圖片地圖在性能優化上有很大的提高,但是使用的並不是很普遍,主要在於他有局限性,首先就是他定義的圖片地圖上的區域坐標時,如果使用手工的方式很難完成並且容易出錯,而且他處理矩形外基本上無法定義其他形狀。而通過DHTML創建的圖片地圖則在IE中無法工作。因為這些方面的原因,圖片地圖的使用量並不大,但有沒有其他方法呢?當然有,跟圖片地圖很類似的,還有一種方法叫做CSS Sprite,人們平時喜歡叫他精靈圖或者雪碧圖,他的原理也是把小圖標之類的整合成一張圖片,但不同的是,他是使用背景圖的方式。
CSS Sprite的實現原理也很簡單,先給一個固定寬高的盒子,然后給他設置背景圖,然后通過調整背景圖的大小和位置,從而來顯示我們小圖片。代碼如下:
<style> #navbar span { width:31px; height:31px; display:inline; float:left; background-image:url(/images/spritebg.gif?t=1490672913); } .home { background-position:0 0; margin-right:4px; margin-left: 4px;} .gifts { background-position:-32px 0; margin-right:4px;} .cart { background-position:-64px 0; margin-right:4px;} .settings { background-position:-96px 0; margin-right:4px;} .help { background-position:-128px 0; margin-right:0px;} </style> <div id="navbar" style="background-color: #F4F5EB; border: 2px ridge #333; width: 180px; height: 32px; padding: 4px 0 4px 0;"> <a href="javascript:alert('Home')" title="Home"><span class="home"></span></a> <a href="javascript:alert('Gifts')" title="Gifts"><span class="gifts"></span></a> <a href="javascript:alert('Cart')" title="Cart"><span class="cart"></span></a> <a href="javascript:alert('Settings')" title="Settings"><span class="settings"></span></a> <a href="javascript:alert('Help')" title="Help"><span class="help"></span></a> </div>
對應的案例地址http://stevesouders.com/examples/sprites.php,同樣把限速調到最高,我們發現他所消耗的時間跟圖片地圖的時間差不多,也是在2000ms左右,而且他有一個好處,就是不需要連續的圖片。我們只需展示其中的一部分就好了。如果一個頁面中有很多這樣的小按鈕,圖標之類的圖片的時候,CSS Sprite絕對是一個很好的解決方案。
除了CSS Sprite和圖片地圖之外,還有一種能減少圖片HTTP請求的方式就是使用內聯圖片(Inline images),就是通過使用data:URL的模式,我們最熟悉的就是把圖片轉成base64的格式,說白了,就是把一張圖片轉化成了一長串數據,瀏覽器在解析的時候會把這數據解析成圖片。代碼如下:
<a href="javascript:alert('Help')" title="Help"><img border=0 src="data:image/gif;base64,R0lGODlhHwAfAPcAAAAAALW1tb2MhL2UhL29tcaUlMbGvc6UWs7OxtZ7ANalY9ata9bWztbW1tbe1t7e1uelGOfn1ufn3ufn5+fv3u+MAO+9Ie/v3u/v5+/v7/fOMff35/f37//nY////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yH5BAEAAAAALAAAAAAfAB8AAAj+AAEIHEgQAwMDARImNMAAA8GHEAdKMEAAgQMMGDFIcICgooSIETEgYJhxAgaTGE0eROAQpMCJCCScnGmyJs2RH0FKINCQ5syfNg0SyPkQA8mgSIGePNiSIIKYNSVMkClV6smqVyc8fbhzgtevXguIHVtAKtipQwcaZSChrVsJBRZo6GChroKyb9syfTn0gYQHfh8IWGDhwAABCuwK+BvYb1qDBgBLBjzAgoLFDgYktiDAwWTAJNc6GE3agQDOpQVAgDCgNGmmGAIwcMBgMgMBAgbMFqxgdefPDxgEwCh7NoPax2kbF3Bg9QEBx5EffxBAZnHj05Pfbg7hOXbtwq3YR/+u/LbzztHL064eO7375KoTQCefnn1F9e/jz6fPYCTGkcYpJ+Btuc03oHEGsITBAwQMSNuD4EEoIQMEPJBRgoDVFlyGguEG3YMc9meATAAINZtnu+0mQAUJtDZacCg6wFNLGhlggGulDaDjbyeSZiOJAi1YEXCSeUbkAx1ZWBSFMXnG2EZ+Oekkkg02pZZQI/7Vll9adukARQ4AWRQGX/K05ZldjnSjmBBhRBsBBKz51kFwzoaRS2r91R8BCiUUp5NW4lmiRhuNN1pbdwraZkYaMRroQwEBADs="></a>
案例地址為:http://stevesouders.com/examples/inline-images.php,限速后響應時間為1500ms左右。
但是當我們把內聯圖片的放在HTML中的時候,他就不能緩存了,尤其是公司logo之類的時候,他就不能緩存,這時候我們就可以把圖片寫在css中,利用css的緩存來實現圖片的緩存。
案例地址為:http://stevesouders.com/examples/inline-css-images.php,限速后響應時間為2500ms左右。
總的來說,對於頁面太多小圖片,小按鈕,小圖標的處理,CSS Sprite最為推薦的,首先就是簡單易操作,而且性能也非常好。
除了優化圖片之外,還有css和js文件的優化,在理想的情況下,最好是只有一個css和一個js,但實際開發中,很多情況下我們都會引入狠多外部的文件,又或者是為了模塊化開發考慮,把js分成了很多個文件。對於這個問題的解決辦法,就是抽取js代碼中有用的代碼,然后整合到一個文件中,不過這種方法對於模塊化開發的人來說是一種倒退。解決的方法是遵守編譯型語言的模式,保持JavaScript的模塊化,而在生成過程中從一組特定的模塊生成一個目標文件。這么說可能有點復雜,簡單來說,就是在寫代碼的時候用模塊化開發的思想,而在實際上線的版本中,則選擇其中有用的代碼上線並且合並。
