本文提到的網站性能指網站的響應速度,這也符合絕大部分人對於網站性能的理解:訪問快速的網站性能好,反之,訪問速度越慢,則網站性能越差。本文總結的優化方法是宏觀的工程層面的方法,並不包含微觀的語言語法層面的方法,例如,JS、CSS的語法優化,這一部分一樣影響網站的性能,但語言語法層面的優化更多的是取決於開發人員的編程水平。html
什麼樣的網站響應速度快呢?其實很容易想到,網站加載資源的速度越快,網站響應速度越快;網站須要加載的資源越少,網站響應速度越快。這就分別對應網站性能優化的兩大方向:資源緩存、資源合併壓縮。當瀏覽器完成資源的加載後,須要進一步解析資源,才能渲染出最終的網頁,因此,瀏覽器的解析機制也是網站性能優化的一個方向。各類優化方法均可以歸類到這三個大方向中。前端
將網站的靜態資源分離,如靜態HTML、圖片Image、樣式CSS、腳本JS等,把靜態資源部署到CDN中,能夠明顯加快這部分資源的加載速度。webpack
HTTP緩存會把瀏覽器加載過的資源緩存到本地,下次加載時,只要緩存的資源沒有過時,就能夠直接使用本地的資源,減小了HTTP請求次數,加快了資源加載速度。具體作法是設置HTTP Header 中的Cache-Control參數。HTTP 1.0 中使用Pragma和Expires兩個參數進行緩存,不過早已不推薦使用。web
用一個HTTP請求去加載一個10M的文件,和把這個文件拆分紅1M的10個文件,用10個HTTP請求並行去加載,哪種方式能更快完成加載?既然提到減小HTTP請求能夠提升網站響應速度,那麼結論貌似應該是用一個HTTP請求的方式更快。其實正確的答案是:不必定!編程
我作了一個小實驗:有兩個html文件,index1.html和index2.html,index1.html中用1個<script>標籤加載一個2M的js文件bundle.js,index2.html中用6個<script>標籤分別加載bundle1.js, bundle2.js …… bundle6.js,這6個js文件由bundle.js平均拆分獲得。分別請求index1.html和index2.html 10次,獲得加載bundle.js的時間和加載bundle1.js 到 bundle6.js的時間(以最後一個js文件加載完成爲結束時間),計算平均加載時間分別爲:1.07s 和 1.87s。瀏覽器
實驗結論證實了,一個HTTTP請求加載一個合併後的資源文件,比多個HTTTP請求併發加載多個資源文件效率高。但結論只是針對平均加載時間而言,對於單次的比較,徹底可能出現相反的結論,例如個人實驗過程當中,單一HTTTP請求加載時間的最大值爲2.36s,超過了第二種加載方式的平均時間1.87s。可能有些人會比較疑惑,爲何並行的效率反而比串行的要低呢?其實,HTTP請求加載資源的瓶頸在帶寬,而不是請求的數量,在一個請求已經利用帶寬很充分的狀況下,增長新的請求並不能減小總體的資源加載時間。緩存
其實,減小HTTP請求來提升網站性能主要是基於如下2個緣由:性能優化
1) HTTP鏈接的創建是比較耗時的,通常須要上百ms,每一個HTTP請求還有必定的網絡延時,須要的HTTP請求越多,這兩部分產生的耗時也就越多。固然,HTTP 1.1 對keep-alive的默認支持,能夠實現鏈接的複用,很大程度上優化了這個問題。服務器
2)每一個HTTP請求都須要附帶額外的數據,好比請求和響應中的頭信息,Cookie信息。當請求的資源很小時,附帶的額外數據可能比實際的資源還大。網絡
合併壓縮JS文件,一方面JS文件數量減小,須要的HTTP請求數也就減小了;另外一方面,壓縮JS文件能夠極大地減少文件體積。可使用webpack等Web構建工具對JS文件進行壓縮合並。
要注意,壓縮合並JS文件並非要把全部的JS文件都打包到一個JS文件中。通常的作法是按照「基礎代碼」+「頁面代碼」分別打包。「基礎代碼」指各個頁面或路由(對單頁面而言)都要用到的通用代碼,「頁面代碼」是隻在某個具體頁面或路由中才會用到的代碼。這樣就能夠實現JS代碼按需加載,避免頁面首屏加載時,由於單一JS文件過大,而影響首屏顯示時間。對單頁面應用來講,還能夠有一個vendor.js的文件,這個文件中的內容是一些用到頻率比較高的第三方庫(如ECharts等),但這些庫並非每一個路由都會用到的,因此並不會被打包到「基礎代碼」中。將這樣的第三方庫從各個路由頁面對應的JS文件中拆分,一是能夠減小全部JS文件的總體大小,由於原本多是A、B等多個文件都會包含的代碼,如今則只須要一份;二是vendor.js只須要被加載一次,後續打開其餘路由時,就能夠不須要再次加載這部分代碼了,起到了資源預加載的做用。
對CSS文件進行合併壓縮,基本原理和作法同JS文件。
1) 使用WebP格式的圖片。WebP是一種支持有損壓縮和無損壓縮的圖片文件格式,派生自圖像編碼格式 VP8。根據 Google 的測試,無損壓縮後的 WebP 比 PNG 文件少了 45% 的文件大小,即便這些 PNG 文件通過其餘壓縮工具壓縮以後,WebP 仍是能夠減小 28% 的文件大小。
2)使用字體圖標IconFont。能夠任意設置Icon圖形的大小和顏色(只能是單色,由於本質上是給字體設置顏色)。
3)使用CSS Sprites將多張圖片合併成一張,從而減小HTTP請求數量。
4)使用Base64直接把圖片編碼成字符串寫入CSS文件,也是從減小HTTP請求數量考慮。但須要注意,Base64編碼的圖片最好是小圖片(最好幾十字節級別的),由於圖片通過Base64編碼後,通常會比原文件更大些。並且太長的Base64編碼字符串也會影響CSS的總體可讀性。
5)對於須要大量圖片的網站,應該把圖片資源單獨部署,並使用不一樣的域名來訪問。由於圖片資源佔帶寬很大,若是把圖片和其餘資源部署到一臺服務器或一個集羣中,服務器端的出口帶寬會受到很大影響。使用不一樣的域名加載圖片資源,能夠更好的利用瀏覽器並行下載的特性,由於瀏覽器對於一個域名下的最大並行請求數是有限制的。
服務端開啓gzip壓縮,能夠減小資源文件在網絡傳輸過程當中的體積大小。
瀏覽器的工做原理很是繁瑣和複雜,要想仔細瞭解,能夠參考這篇經典的文章How browers work。
結合文章和我本身實驗驗證,簡單來講的話,當瀏覽器載入一個HTML文件後,
1)會先將加載HTML中引用的全部外部資源(JS、CSS文件等)的請求放到一個隊列中,而後瀏覽器經過多個線程(具體由瀏覽器設置決定)併發加載這些資源。
2)緊接着對HTML進行自上而下的解析。
3)當解析到<script>標籤時,若是標籤內是內嵌到HTML中的JS代碼,會直接執行這部分代碼;若是標籤引用了外部的JS文件,且這個文件此時尚未下載完成,解析過程會被阻塞,直到JS文件下載完成,而後解析執行JS代碼,以後纔會繼續HTML的解析過程;若是標籤引用了外部的JS文件,但此時這個JS文件已經下載完成,則會直接執行這部分JS代碼,並不會阻塞HTML的解析(能夠理解成此時JS代碼的執行本就屬於HTML解析這個<script>標籤的過程)。
4) 當解析到<link>標籤時,無論<link>中引用的外部CSS資源是否加載完成,都不會阻塞HTML繼續向下解析。
這裏有2個須要注意的地方:
1)由於JS的加載會阻塞HTML向下解析,因此多個JS文件中代碼的執行順序,是和他們在HTML中的位置順序保持一致的。例如HTML中,從上向下依次引入a.js, b.js, a.js的文件大小遠大於b.js,這樣b.js文件極可能先完成加載,可是並不會先於a.js中的代碼執行,由於在a.js加載、解析、並執行完成前,HTML的解析是處於阻塞的,b.js所在的<script>標籤天然也不會被解析執行。若是不但願加載外部JS文件阻塞HTML的解析,可使用script標籤的defer或async屬性,這裏就再也不展開。
2)全部引用的外部腳本或樣式文件,在HTML開始解析前,就已經加入到瀏覽器的請求隊列中,因此多個外部資源開始加載的起始時間通常不會相差很大,除非請求的外部資源數量不少,超過了瀏覽器的併發請求數。
基於瀏覽器工做原理的經常使用優化性能的方法有2個:
1)引用外部CSS文件的link標籤,通常會寫在<head>內,這是爲了能儘早的使<body>內的元素獲取樣式,優化視覺顯示效果。
2)引用外部JS文件的script標籤,通常會寫在<body>底部,這是爲了不HTML的解析被阻塞,從而使頁面元素更快的顯示出來。須要注意,雖然script寫在<body>底部,但這不意味着<body>內的其餘元素都解析完成後纔開始加載這些JS文件,這些JS文件依然會在HTML開始解析前,就被加入到請求隊列中。
以上就是從資源緩存、資源合併壓縮和瀏覽器解析原理三個維度出發,經常使用的優化網站性能的實踐方法
學習過程當中遇到什麼問題或者想獲取學習資源的話,歡迎加入學習交流羣
343599877,咱們一塊兒學前端!