400% 的飛躍-web 頁面載入速度優化實戰

rapospectre發表於2016-09-28

前言

一個網站的載入速度有多重要? 反正我相信之前來博主網站的人至少有 50% 在載入完成前關閉了本站。 為啥捏? 看圖

高清大圖

首頁完整載入時間 8.18s,看來能進來看博主網站的人都是真愛呀,哈哈。 正常來講一個網頁 4s 載入不完就會流失很大一部分使用者,而博主的網站載入時間竟然達到了 8s 還是在電腦端,如果在移動端,載入時間會更久,體驗會更差。 這樣的話網站做得再難看批判者進不來不是白搭嘛,於是針對 web 頁面載入速度的優化迫在眉睫。

基於博主以前優化過其他網站,於是博主準備把這次的優化過程記錄下來分享給大家借鑑。

1. 頁面分析

先來看優化前的頁面:

載入時間 8.18s ,一共 33 個 請求,載入 1.38MB 。 可以看到對於網速較慢的瀏覽者光載入資源就需要 5s 以上,再加上 33 個請求切換開銷,簡直不能愉快的玩耍。 所以接下來的優化手段就要從載入流量和請求數量入手:

2. 優化圖片

圖片在網路流量中佔有很大的比重,因此優化圖片對於減少流量有著至關重要的作用。

合併小圖片:

很多頁面有很多小圖示,一個一個載入就相當於一個一個請求,將這些小圖片合併成一個大圖片,用css 控制顯示範圍,這樣就只需要一個請求即可載入完所有小圖片,瞬間就會減少很多網路請求。

優化圖片格式:

很多圖片沒有經過優化直接上傳到網頁中會佔用很多額外的流量,比如一張螢幕大小的截圖,用截圖工具直接截圖後的大小大概有 1MB ,此時直接上傳到網頁中就直接佔用了 1MB 流量,但其實我們完全可以只犧牲它 40% 的質量換取縮小 10 倍的大小,網上有很多轉化 web 圖片的網站,當然如果你有 photoshop 的話完全可以自己匯出:

將圖片在 ps 中開啟,然後點選選單欄 “檔案” 選單,選擇 “儲存為 web 所用格式”,出現如下對話方塊:

一般情況下 jpg 圖片選擇品質中即可,png 格式圖片選擇 png8 即可,但注意有透明背景的 png 圖片要選擇 png24 ,否則透明背景中會出現白邊,gif 圖片選擇 gif64 無仿色即可。

一般經過優化的圖片大小至少會有 3倍 之差,圖片原大小越大優化的結果會越好。

博主的網站最顯眼的圖片就是頁首上那個幽鬼的圖片啦,所以就先拿它開刀,經過以上步驟優化:

瞬間減小 4 倍,實際效果可以看看,代表著博主門面的圖片經過優化後和優化前顯示效果並沒有明顯區別,而檔案大小卻相差了 4 倍。

3. 使用免費 cdn 載入第三方資源

所有網站都會用到第三方資源,對於第三方資源,如果選擇讓自己的伺服器提供,那麼對於小型站點,本就不大的頻寬相當一部分還要被公共資源佔用,無形之中壓縮了伺服器頻寬,如果把這部分資源讓第三方 cdn 提供,那麼對於網站載入速度會有不小的提升。

博主選用的是 bootstrap 中文站提供的 cdn 靜態庫,博主看過不少國內 cdn 靜態庫,可以說 bootstrap 家的還是很良心的,更新及時,資源現在也很豐富,基本博主用的三方資源都能在上面找到,於是接下來就是搜尋靜態資源 + 替換靜態資源:

<script src="/s/js/jquery.min.js"></script>
改為
<script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>複製程式碼

這裡不要寫協議頭,讓網頁自動判斷使用 http 還是 https ( 關於 https 網站的部署可以看博主之前的文章: 給你的網站穿上外衣- HTTPS 免費部署指南

4. 使用 cdn 儲存靜態資源

一般網站 90% 的流量都用於靜態資源的載入,除了用免費 cdn 載入第三方資源,還可以自己申請雲空間儲存自己的靜態資源,進一步減小伺服器的開銷,讓伺服器只專注於提供資料或者網頁渲染服務。 比如博主使用的是 X牛 ,將自己的圖片什麼都存在 x牛上,每個月都有免費流量,對於個人網站來說應該夠用。

5. 合併壓縮 js css

除去引用公共庫,網頁中還有許多自己寫的 js 與 css,如果我們直接把開發環境的檔案拿來用無疑很浪費流量,因此在編寫好網頁測試完畢後,我們應該將 css 和 js 壓縮合併成一個或者幾個檔案,這樣既減少了請求次數又減少了流量消耗,一箭雙鵰。 當然還有 html 壓縮,不過 ms 現階段還有一些坑,就先不用了。 說到合併壓縮,第一時間播追就想到了 webpack ,前端工程化神器,簡單配置一下就可以完全搞定任務:

博主網站自己的 js 工程檔案放在 /webroot/static/src/js/ 中,假如我們要將壓縮合並後的檔案放在 /webroot/static/dist/js/ 中:

/webroot/ 下新建資料夾 webpack, 進入資料夾,新建檔案 package.json:

{
  "name": "RaPo3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "rapospectre",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^0.24.0",
    "style-loader": "^0.13.1",
    "webpack": "^1.13.2",
    "webpack-dev-server": "^1.15.1"
  }
}複製程式碼

儲存後執行:

npm install
//或
cnpm install
//如果你有的話複製程式碼

然後新建 webpack 配置檔案 webpack.config.js:

var webpack = require('webpack');
module.exports = {
    entry: {
        base: ['../static/js/src/http.js', '../static/js/stickUp.min.js', '../static/js/src/base.js'],
        index: ['../static/js/src/index.js'],
        detail: ['../static/js/editormd.js', '../static/js/src/article.js'],
        know: ['../static/js/editormd.js', '../static/js/src/know.js'],
        list: ['../static/js/src/list.js']

    },
    output: {
        path: '../static/js/dist/',
        filename: '[name].js'
    },
    plugins: [
        new webpack.optimize.UglifyJsPlugin({
            output: {
                comments: false
            },
            compress: {
                warnings: true
            }
        }),
    ]
}複製程式碼

這裡要注意的是如果你的 js 檔案間的引用是傳統的 html 引入後引用那麼在這裡合併時記得把你被引用的方法\物件等等設定為全域性,比如 b.js 要引用 a.js 中的函式 c,合併前要在 a.js 中加上( 當然如果你一直用 es6/node 寫 js 就不用看這裡了 ):

window.c = c;
或
this.c = c;複製程式碼

不然 c 就會被當作區域性函式封裝起來。

改完後執行 webpack 提示成功後看到 dist 目錄裡已經輸出了合併壓縮好的檔案,之前 12kb 的檔案經過壓縮合並後只有 6kb 大小,然後我們將其替換到網頁中即可。

6. 程式碼優化

頁面程式碼的優化對於頁面載入速度也有不小的影響,最廣為人知的:

HTML頭部的JavaScript和寫在HTML標籤中的Style會阻塞頁面的渲染,因此CSS放在頁面頭部並使用Link方式引入,JavaScript的引入放在頁面尾

其次還有:

  1. 按需載入,把統計、分享等 js 在頁面 onload 後再進行載入,可以提高訪問速度;
  2. 優化 cookie ,減少 cookie 體積;
  3. 避免 400% 的飛躍-web 頁面載入速度優化實戰 的 src 為空;
  4. 儘量避免設定圖片大小,多次重設圖片大小會引發圖片的多次重繪,影響效能;
  5. 合理使用display屬性:
    a.display:inline後不應該再使用width、height、margin、padding以及float
    b.display:inline-block後不應該再使用float
    c.display:block後不應該再使用vertical-align
    d.display:table-*後不應該再使用margin或者float複製程式碼
  1. 不濫用Float 和 web 字型;
  2. 儘量使用CSS3動畫;
  3. 使用 ajax 非同步載入部分請求;

7. HTTP2 與 gzip

HTTP2 是以 SPDY 為基礎開發的。 SPDY 系列協議由谷歌開發,於 2009 年公開。它的設計目標就是降低 50% 的頁面載入時間,所以 HTTP2 在很大程度也是為了優化頁面載入時間,同時 HTTP2 支援多路複用,簡單說就是所有的請求都通過一個 TCP 連線併發完成。 而 gzip 大家都不陌生,就是一種壓縮網頁的技術,當然壓縮網頁進行傳輸的代價就是給伺服器增加一些壓縮的負擔,當然這種犧牲是值得的。

如何開啟 HTTP2 與 gzip? 博主的網站基於 nginx + uWSGI 進行服務,因此只要在 nginx 開啟 HTTP2 與 gzip 就好:

開啟 HTTP2

nginx 1.9.5 之後才支援 HTTP2 ,而且需要配置編譯引數,關於 nginx 開啟 HTTP2 請直接移步博主之前的文章: nginx 配置 http2

開啟 gzip

直接開啟 nginx 配置檔案, 比如博主的在 /etc/nginx/nginx.conf, 然後加上:

server{
        gzip  on;
        gzip_comp_level 6;
        gzip_proxied any;
        gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript application/x-font-woff;
        }複製程式碼

然後重啟 nginx 即可

最後,讓我們清除快取,再次開啟網站:

總載入流量 527kb ,頁面完成載入時間 1.84s,對比之前載入時間 8.18s ,1.38MB 流量,整體時間提升了 4 倍多!用手機端訪問測試,簡直快的飛起,不信你也來訪問( 騙流量臉 )試試呀~

最後,附上本文網站的原始碼以及目錄結構,可以通過 commit 記錄更加直觀的看到優化的過程:

github.com/bluedazzle/…

歡迎來顆 star 哈哈。

作者:rapospectre

相關文章