網(wǎng)站性能優(yōu)化你需知道的東西

本文提到的網(wǎng)站性能指網(wǎng)站的響應(yīng)速度,這也符合絕大部分人對于網(wǎng)站性能的理解:訪問快速的網(wǎng)站性能好,反之,訪問速度越慢,則網(wǎng)站性能越差。本文總結(jié)的優(yōu)化方法是宏觀的工程層面的方法,并不包含微觀的語言語法層面的方法,例如,JS、CSS的語法優(yōu)化,這一部分同樣影響網(wǎng)站的性能,但語言語法層面的優(yōu)化更多的是取決于開發(fā)人員的編程水平。


1.資源緩存

1.1 使用CDN

將網(wǎng)站的靜態(tài)資源分離,如靜態(tài)HTML、圖片Image、樣式CSS、腳本JS等,把靜態(tài)資源部署到CDN中,可以明顯加快這部分資源的加載速度。

1.2 利用HTTP緩存機(jī)制

HTTP緩存會把瀏覽器加載過的資源緩存到本地,下次加載時(shí),只要緩存的資源沒有過期,就可以直接使用本地的資源,減少了HTTP請求次數(shù),加快了資源加載速度。具體做法是設(shè)置HTTP

Header 中的Cache-Control參數(shù)。HTTP 1.0 中使用Pragma和Expires兩個(gè)參數(shù)進(jìn)行緩存,不過早已不推薦使用。

2. 資源的合并壓縮

我做了一個(gè)小實(shí)驗(yàn):有兩個(gè)html文件,index1.html和index2.html,index1.html中用1個(gè)標(biāo)簽加載一個(gè)2M的js文件bundle.js,index2.html中用6個(gè)標(biāo)簽分別加載bundle1.js,

bundle2.js ……

bundle6.js,這6個(gè)js文件由bundle.js平均拆分得到。分別請求index1.html和index2.html

10次,得到加載bundle.js的時(shí)間和加載bundle1.js 到

bundle6.js的時(shí)間(以最后一個(gè)js文件加載完成為結(jié)束時(shí)間),計(jì)算平均加載時(shí)間分別為:1.07s 和 1.87s。

實(shí)驗(yàn)結(jié)論證明了,一個(gè)HTTTP請求加載一個(gè)合并后的資源文件,比多個(gè)HTTTP請求并發(fā)加載多個(gè)資源文件效率高。但結(jié)論只是針對平均加載時(shí)間而言,對于單次的比較,完全可能出現(xiàn)相反的結(jié)論,例如我的實(shí)驗(yàn)過程中,單一HTTTP請求加載時(shí)間的最大值為2.36s,超過了第二種加載方式的平均時(shí)間1.87s。可能有些人會比較疑惑,為什么并行的效率反而比串行的要低呢?其實(shí),HTTP請求加載資源的瓶頸在帶寬,而不是請求的數(shù)量,在一個(gè)請求已經(jīng)利用帶寬很充分的情況下,增加新的請求并不能減少整體的資源加載時(shí)間。

其實(shí),減少HTTP請求來提高網(wǎng)站性能主要是基于以下2個(gè)原因:

1) HTTP連接的建立是比較耗時(shí)的,一般需要上百ms,每個(gè)HTTP請求還有一定的網(wǎng)絡(luò)延時(shí),需要的HTTP請求越多,這兩部分產(chǎn)生的耗時(shí)也就越多。當(dāng)然,HTTP 1.1 對keep-alive的默認(rèn)支持,可以實(shí)現(xiàn)連接的復(fù)用,很大程度上優(yōu)化了這個(gè)問題。

2)每個(gè)HTTP請求都需要附帶額外的數(shù)據(jù),比如請求和響應(yīng)中的頭信息,Cookie信息。當(dāng)請求的資源很小時(shí),附帶的額外數(shù)據(jù)可能比實(shí)際的資源還大。

2.2 JS文件

合并壓縮JS文件,一方面JS文件數(shù)量減少,需要的HTTP請求數(shù)也就減少了;另一方面,壓縮JS文件可以極大地減小文件體積??梢允褂脀ebpack等Web構(gòu)建工具對JS文件進(jìn)行壓縮合并。

要注意,壓縮合并JS文件并不是要把所有的JS文件都打包到一個(gè)JS文件中。一般的做法是按照“基礎(chǔ)代碼”+“頁面代碼”分別打包?!盎A(chǔ)代碼”指各個(gè)頁面或路由(對單頁面而言)都要用到的通用代碼,“頁面代碼”是只在某個(gè)具體頁面或路由中才會用到的代碼。這樣就可以實(shí)現(xiàn)JS代碼按需加載,避免頁面首屏加載時(shí),因?yàn)閱我籎S文件過大,而影響首屏顯示時(shí)間。對單頁面應(yīng)用來說,還可以有一個(gè)vendor.js的文件,這個(gè)文件中的內(nèi)容是一些用到頻率比較高的第三方庫(如ECharts等),但這些庫并不是每個(gè)路由都會用到的,所以并不會被打包到“基礎(chǔ)代碼”中。將這樣的第三方庫從各個(gè)路由頁面對應(yīng)的JS文件中拆分,一是可以減少所有JS文件的整體大小,因?yàn)楸緛砜赡苁茿、B等多個(gè)文件都會包含的代碼,現(xiàn)在則只需要一份;二是vendor.js只需要被加載一次,后續(xù)打開其他路由時(shí),就可以不需要再次加載這部分代碼了,起到了資源預(yù)加載的作用。

2.3 CSS文件

對CSS文件進(jìn)行合并壓縮,基本原理和做法同JS文件。

2.4 圖片

1) 使用WebP格式的圖片。WebP是一種支持有損壓縮和無損壓縮的圖片文件格式,派生自圖像編碼格式 VP8。根據(jù) Google

的測試,無損壓縮后的 WebP 比 PNG 文件少了 45% 的文件大小,即使這些 PNG 文件經(jīng)過其他壓縮工具壓縮之后,WebP 還是可以減少

28% 的文件大小。

2)使用字體圖標(biāo)IconFont??梢匀我庠O(shè)置Icon圖形的大小和顏色(只能是單色,因?yàn)楸举|(zhì)上是給字體設(shè)置顏色)。

3)使用CSS Sprites將多張圖片合并成一張,從而減少HTTP請求數(shù)量。

4)使用Base64直接把圖片編碼成字符串寫入CSS文件,也是從減少HTTP請求數(shù)量考慮。但需要注意,Base64編碼的圖片最好是小圖片(最好幾十字節(jié)級別的),因?yàn)閳D片經(jīng)過Base64編碼后,一般會比原文件更大些。而且太長的Base64編碼字符串也會影響CSS的整體可讀性。

5)對于需要大量圖片的網(wǎng)站,應(yīng)該把圖片資源單獨(dú)部署,并使用不同的域名來訪問。因?yàn)閳D片資源占帶寬很大,如果把圖片和其他資源部署到一臺服務(wù)器或一個(gè)集群中,服務(wù)器端的出口帶寬會受到很大影響。使用不同的域名加載圖片資源,可以更好的利用瀏覽器并行下載的特性,因?yàn)闉g覽器對于一個(gè)域名下的最大并行請求數(shù)是有限制的。

2.5 服務(wù)器端開啟gzip

服務(wù)端開啟gzip壓縮,可以減少資源文件在網(wǎng)絡(luò)傳輸過程中的體積大小。

3.瀏覽器加載、解析、渲染機(jī)制


瀏覽器的工作原理非常繁瑣和復(fù)雜,要想仔細(xì)了解,可以參考這篇經(jīng)典的文章How browers work

結(jié)合文章和我自己實(shí)驗(yàn)驗(yàn)證,簡單來說的話,當(dāng)瀏覽器載入一個(gè)HTML文件后,

1)會先將加載HTML中引用的所有外部資源(JS、CSS文件等)的請求放到一個(gè)隊(duì)列中,然后瀏覽器通過多個(gè)線程(具體由瀏覽器設(shè)置決定)并發(fā)加載這些資源。

2)緊接著對HTML進(jìn)行自上而下的解析。

3)當(dāng)解析到<script>標(biāo)簽時(shí),如果標(biāo)簽內(nèi)是內(nèi)嵌到HTML中的JS代碼,會直接執(zhí)行這部分代碼;如果標(biāo)簽引用了外部的JS文件,且這個(gè)文件此時(shí)還沒有下載完成,解析過程會被阻塞,直到JS文件下載完成,然后解析執(zhí)行JS代碼,之后才會繼續(xù)HTML的解析過程;如果標(biāo)簽引用了外部的JS文件,但此時(shí)這個(gè)JS文件已經(jīng)下載完成,則會直接執(zhí)行這部分JS代碼,并不會阻塞HTML的解析(可以理解成此時(shí)JS代碼的執(zhí)行本就屬于HTML解析這個(gè)

4) 當(dāng)解析到<link>標(biāo)簽時(shí),不管<link>中引用的外部CSS資源是否加載完成,都不會阻塞HTML繼續(xù)向下解析。

1)因?yàn)镴S的加載會阻塞HTML向下解析,所以多個(gè)JS文件中代碼的執(zhí)行順序,是和他們在HTML中的位置順序保持一致的。例如HTML中,從上向下依次引入a.js,b.js, a.js的文件大小遠(yuǎn)大于b.js,這樣b.js文件很可能先完成加載,但是并不會先于a.js中的代碼執(zhí)行,因?yàn)樵赼.js加載、解析、并執(zhí)行完成前,HTML的解析是處于阻塞的,b.js所在的<script>標(biāo)簽自然也不會被解析執(zhí)行。如果不希望加載外部JS文件阻塞HTML的解析,可以使用script標(biāo)簽的defer或async屬性,這里就不再展開。

2)所有引用的外部腳本或樣式文件,在HTML開始解析前,就已經(jīng)加入到瀏覽器的請求隊(duì)列中,所以多個(gè)外部資源開始加載的起始時(shí)間一般不會相差很大,除非請求的外部資源數(shù)量很多,超過了瀏覽器的并發(fā)請求數(shù)。

1)引用外部CSS文件的link標(biāo)簽,一般會寫在<head>內(nèi),這是為了能盡早的使<body>內(nèi)的元素獲取樣式,優(yōu)化視覺顯示效果。

2)引用外部JS文件的script標(biāo)簽,一般會寫在底部,這是為了避免HTML的解析被阻塞,從而使頁面元素更快的顯示出來。需要注意,雖然script寫在底部,但這不意味著內(nèi)的其他元素都解析完成后才開始加載這些JS文件,這些JS文件依然會在HTML開始解析前,就被加入到請求隊(duì)列中。

以上就是從資源緩存、資源合并壓縮和瀏覽器解析原理三個(gè)維度出發(fā),常用的優(yōu)化網(wǎng)站性能的實(shí)踐方法
標(biāo)簽的過程)。標(biāo)簽時(shí),如果標(biāo)簽內(nèi)是內(nèi)嵌到HTML中的JS代碼,會直接執(zhí)行這部分代碼;如果標(biāo)簽引用了外部的JS文件,且這個(gè)文件此時(shí)還沒有下載完成,解析過程會被阻塞,直到JS文件下載完成,然后解析執(zhí)行JS代碼,之后才會繼續(xù)HTML的解析過程;如果標(biāo)簽引用了外部的JS文件,但此時(shí)這個(gè)JS文件已經(jīng)下載完成,則會直接執(zhí)行這部分JS代碼,并不會阻塞HTML的解析(可以理解成此時(shí)JS代碼的執(zhí)行本就屬于HTML解析這個(gè)標(biāo)簽的過程)
標(biāo)簽時(shí),如果標(biāo)簽內(nèi)是內(nèi)嵌到HTML中的JS代碼,會直接執(zhí)行這部分代碼;如果標(biāo)簽引用了外部的JS文件,且這個(gè)文件此時(shí)還沒有下載完成,解析過程會被阻塞,直到JS文件下載完成,然后解析執(zhí)行JS代碼,之后才會繼續(xù)HTML的解析過程;如果標(biāo)簽引用了外部的JS文件,但此時(shí)這個(gè)JS文件已經(jīng)下載完成,則會直接執(zhí)行這部分JS代碼,并不會阻塞HTML的解析(可以理解成此時(shí)JS代碼的執(zhí)行本就屬于HTML解析這個(gè)標(biāo)簽的過程)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,063評論 25 709
  • 網(wǎng)站優(yōu)化離不開前后端的互相協(xié)作,但是對于前端工程師來說,在保證后端技術(shù)方案不變時(shí),能不能只利用前端技術(shù)來優(yōu)化網(wǎng)站呢...
    留七七閱讀 6,585評論 0 31
  • 聽閨密說這部跨世紀(jì)的電影劇情有點(diǎn)破碎,但沖著安叔的名號,我做好“看不懂然后會睡覺”的心理準(zhǔn)備后,還是走進(jìn)影院看《比...
    胖格格格閱讀 529評論 0 0
  • 感恩5月17日 1.感恩女兒在我十分疲勞又心情不好的夜晚,替我把床鋪好。那一刻的驚喜勝過所有"禮物"。感動的眼淚幾...
    盈洋洋閱讀 322評論 0 0
  • 這應(yīng)該是我長這么大以來,第一次一個(gè)人過元宵節(jié)吧。與很多人想象中的不同,我并沒有什么所謂的失落感,孤獨(dú)感之類的。相反...
    辰星劇社馬沖閱讀 347評論 8 3

友情鏈接更多精彩內(nèi)容