網站性能優化實戰篇

閱讀理由:經驗之談,從理論到實踐。javascript

前情摘要

網站優化是前端開發的重中之重,可是優化細節卻十分繁雜,沒有好的思路,優化很難高效的開展。css

本文將以實際網站來作參考,手把手教你如何一步步作好網站優化。html

這不是一篇 基礎網站優化 文章,繼續下文前,請肯定已經作了以下基本優化:前端

  1. 圖片壓縮、合併
  2. 代碼精簡、混淆
  3. 減小 iframe 使用
  4. 避免圖片 src 爲空
  5. 減小 HTTP 請求數
  6. 避免重定向
  7. 樣式表放頁頭、腳本放底部

優化的意義

咱們能夠從兩個角度來看這個問題:java

  1. 用戶角度

    網站優化可以讓頁面加載得更快,響應更加及時,極大提高用戶體驗。react

  2. 服務商角度

    優化會減小頁面資源請求數,減少請求資源所佔帶寬大小,從而節省可觀的帶寬資源。webpack

網站優化的目標是:減小網站加載時間,提升響應速度。

那麼網站加載速度和用戶體驗又有着怎樣的關係呢?咱們來看下面這張圖:nginx

性能優化

Google 和亞馬遜的研究代表,Google 頁面加載的時間從 0.4 秒提高到 0.9 秒致使丟失了 20% 流量和廣告收入,對於亞馬遜,頁面加載時間每增長 100ms 就意味着 1% 的銷售額損失。git

可見,頁面的加載速度對於用戶有着相當重要的影響。

一個好的交互效果多是這樣的:github

性能優化

分析網站性能瓶頸

1. 打包文件大小

2. 打包文件目錄

.
├── favicon.ico
├── index.html
├── manifest.json
├── static
│   ├── DIN-Medium.1bbe3460.otf
│   ├── DIN-Regular.799221d7.otf
│   └── logo.c57d38d0.png
├── umi.css
├── umi.css.map
├── umi.js
└── umi.js.map
須要注意:生產環境不要開啓 SOURCEMAP

3. 靜態資源加載時間

4. 資源瀑布 Waterfall

waterfall

TTFB 全稱 Time To First Byte:是指網絡請求被髮起到從服務器接收到第一個字節的這段時間,它包含了 TCP 鏈接時間、發送 HTTP 請求時間和得到響應消息第一個字節的時間。

Content Download:即下載內容所須要的時間。

頁面一接口狀況:

wrong

頁面二接口狀況:

history

用戶下載內容所須要的時間,受限於服務器的資源、資源的大小以及用戶的網絡速度。所以,咱們暫時不討論這方面的內容。

5. 分析工具

經過 webpack 打包,分析一下大文件構成。

6.YSlow 或者 PageSpeed

咱們能夠經過 Google PageSpeed Insights API Extension 來對網站總體性能 作一下評估,按照建議去作一些高效優化。

加載時間概況:

speed1

影響網站加載因素:

緩存策略問題:

speed3

DOM 節點:

關鍵路徑:

speed5

主線程狀況:

經過策略解決問題

1. favicon.ico 404 問題 ✓

2. 去除調試工具代碼 eruda,線上環境是不須要的 ✓

3. 圖片合併或者多個 svg

建議使用 webpack-spritesmith,簡單使用以下:

plugins: [
  new SpritesmithPlugin({
    src: {
        cwd: path.resolve(__dirname, 'src/ico'),
        glob: '*.png'
    },
    target: {
        image: path.resolve(__dirname, 'src/spritesmith-generated/jartto.png'),
        css: path.resolve(__dirname, 'src/spritesmith-generated/jartto.styl')
    },
    apiOptions: {
        cssImageRef: "~jartto.png"
    }
  })
]

4. 大文件拆分 ✓

從上圖分析得出,大文件主要包含:dist.jslottie.jslodash.jsloading.json 等文件。因此咱們從這幾個文件入手,逐個優化:

  • moment.js - 配置 moment 忽略本地化,可減小 70kb
ignoreMomentLocale: true
  • dist.js - 在給單頁應用作按需加載優化時,通常採用如下原則:

    1. 把整個網站劃分紅一個個小功能,再按照每一個功能的相關程度把它們分紅幾類。
    2. 把每一類合併爲一個 Chunk,按需加載對應的 Chunk
    3. 對於用戶首次打開你的網站時須要看到的畫面所對應的功能,不要對它們作按需加載,而是放到執行入口所在的 Chunk 中,以下降用戶能感知的網頁加載時間。
    4. 對於個別依賴大量代碼的功能點,例如依賴 Chart.js 去畫圖表、依賴 flv.js 去播放視頻的功能點,可再對其進行按需加載。
  • lottie.js - 分離減小 60kb

    externals: {
        lottie : 'react-lottie',
    }
  • lodash.js

    externals: {
    lodash : {
        commonjs: 'lodash',
        amd: 'lodash',
        root: '_' // indicates global variable
    }
    }
  • 動態導入以及文件拆分

    dynamicImport: {
        webpackChunkName: true,
        loadingComponent: './components/Loading/jartto.js',
    }

按照上面咱們一步步處理後,從新打包分析一下文件構成:

這裏爲何沒有繼續拆分 dist.js,是由於目前階段沒有好的方案,須要對代碼作不少調整,因此暫且保留。相關信息能夠在 Ant-Design Issuse Svg icons make bunlde size too large 中查看解決方案。

5. 存放 CDN

  • loading.json 大小54kb ✓
  • svg 替換 2 倍圖 ✓
  • 刪除項目冗餘圖片 ✓

6. 優化 TTFB

  • 減小 DNS 查詢
  • 使用 CDN
  • 提前 Flush
  • 添加週期頭

7. 移除阻塞渲染的資源

  • css 預加載 preload

    <link rel="preload">
  • 異步加載第三方資源

    <script async src="https://cdn.jartto.wang/fastclick.js"></script>

    沒有 async 屬性,script 將當即獲取(下載)並執行,期間阻塞了瀏覽器的後續處理。
    若是有 async 屬性,那麼 script 將被異步下載並執行,同時瀏覽器繼續後續的處理。

8. 確保文本在網頁字體加載期間保持可見狀態

利用 font-display 這項 CSS 功能,確保文本在網頁字體加載期間始終對用戶可見。

@font-face {
    font-family: 'Arvo';
    font-display: auto;
    src:local('Arvo'),url(https://fonts.jartto.wang/fonts/temp.woff2)format('woff2');
}

9.採用高效的緩存策略提供靜態資源

延長緩存期限可加快重訪網頁的速度。

DNS TTL(Time-To-Live) 簡單的說:它表示一條域名解析記錄在 DNS 服務器上的緩存時間。

  • 當各地的 DNS 服務器接受到解析請求時,就會向域名指定的 DNS 服務器發出解析請求從而得到解析記錄。
  • 在得到這個記錄以後,記錄會在 DNS 服務器中保存一段時間,這段時間內若是再接到這個域名的解析請求,DNS 服務器將再也不向 DNS 服務器發出請求,而是直接返回剛纔得到的記錄。
這個記錄在 DNS 服務器上保留的時間,就是 TTL 值。

因此通常更新域名解析的步驟以下:

  • 先查看域名當前的 TTL 值。
  • 修改 TTL 值爲可設定的最小值,建議爲 60 秒。
  • 等待一天,保證各地的 DNS 服務器緩存都過時並更新了記錄。
  • 設置修改 DNS 解析到新的記錄,這個時候各地的 DNS 就能以最快的速度更新到新的記錄。
  • 確認各地的 DNS 已經更新完成後,再 TTL 值設置成經常使用的值(如: TTL=86400)。

以下圖,TTL 值設置的最佳實踐,可供參考:

後文咱們會詳細介紹 DNS 相關內容,歡迎各位童鞋關注。

10. 避免 DOM 規模過大

  • 網頁包含的 DOM 節點最好少於 1500 個左右。
  • 理想情況是,樹深度少於 32 個元素,且少於 60 個子/父元素。
  • 大型 DOM 可能會增長內存使用量、致使樣式計算用時延長併產生高昂的佈局重排費用。

11. 最大限度地縮短關鍵請求深度

關鍵請求鏈 顯示了以高優先級加載的資源。

咱們能夠經過:縮短鏈長、縮減資源的下載文件大小,或者推遲下載沒必要要的資源,從而提升網頁加載速度。

HTML 解析過程當中遇到一個 script 標記時,它會暫停 DOM 構建,將控制權移交給 JavaScript 引擎,等 JavaScript 引擎運行完畢,瀏覽器再從中斷的地方恢復 DOM 構建。

也就是說,執行內聯的 JavaScript 會阻塞頁面的首次渲染。

在關鍵渲染路徑中,咱們一般要關注三個點:

  • 頁面首次渲染須要的關鍵資源數量。
  • 關鍵資源的大小。
  • 關鍵渲染路徑的往返次數(Roundtrip)。
咱們的策略也很是簡單,就是減小關鍵資源數量,下降資源大小,減小關鍵路徑的往返次數。

優化關鍵渲染路徑的常規步驟以下:

  1. 對關鍵路徑進行分析和特性描述:資源數、字節數、長度。
  2. 最大限度減小關鍵資源的數量:刪除它們,延遲它們的下載,將它們標記爲異步等。
  3. 優化關鍵字節數以縮短下載時間(往返次數)。
  4. 優化其他關鍵資源的加載順序:您須要儘早下載全部關鍵資源,以縮短關鍵路徑長度。

更多詳情,請參考前端性能優化—關鍵渲染路徑

12. 最大限度地減小主線程工做

考慮減小爲解析、編譯和執行 JS 而花費的時間。咱們能夠提供較小的 JS 負載來實現此目標。

13. 最優配置 nginx

  1. gzip 配置
gzip  on;
gzip_min_length  1k;
gzip_buffers     4 8k;
gzip_http_version 1.1;
gzip_comp_level 4;
gzip_types text/plain text/css application/json image/png image/x-icon application/javascript application/x-javascript text/javascript text/xml application/xml application/xml+rss text/cache-manifest application/octet-stream;
gzip_vary on;
  1. nginx 開啓緩存

若是你對瀏覽器緩存還不太清楚,歡迎移步聊一聊瀏覽器緩存機制。

location ~.*\.(html|htm|js|css|gif|jpg|jpeg|png|bmp|swf|ico|json|otf)$ {
  root /var/www/jartto_web/;
  index index.html;
  expires 1d;
}
Nginx 能很是有效地直接處理靜態內容。在靜態文件和 Nginx 在同一主機的狀況下,這種特性尤其有用。

效果如何?

優化前:網站評分 27 ,首次內容繪製 6.9 秒

網站評分:

網站評分

加載概況:

優化後:網站評分 70 ,首次內容繪製 1.6 秒

網站評分:

加載概況:

固然,優化還能夠作更多,咱們儘可能讓網站的評分接近 100 分,譬如:

網站評分:

加載概況:

總結

咱們從頭優化下來,作了很多代碼改動,也達到了不錯的效果。可是有幾點仍是須要注意:

1. 儘量減小白屏出現時間

骨架圖解決 webview 加載頁面過長的白屏過程。

2. 關注整站性能,如 TTFB

服務端接口也須要同步優化,而不要僅僅依賴前端單方面優化。

3. 按照使用狀況加載優先使用的資源

  • css 預加載
  • font 預加載
  • js 預加載
  • 圖片懶加載

4. 高效利用 DNSCDN

  • 增長緩存時間
  • DNS 預解析

網站優化歷來不是一蹴而就,須要不斷的去優化細節,不斷的摸索嘗試。從個人角度來看,其實優化更像是在網站性能和加載速度之間找到一個平衡點。譬如,文中咱們爲了優化文件打包大小,進行了大文件拆分。隨之而來的問題就是拆分後的文件可能還會對某些文件有依賴,那麼就影響到了關鍵渲染路徑。

因此,優化不存在什麼奇技淫巧,不斷的去嘗試,找到這個最佳優化點,這纔是根本。

轉載自: Jartto's blog

做者:jartto

相關文章
相關標籤/搜索