實踐指南-前端效能提升 270%

凹凸實驗室發表於2023-04-13

一、背景

當我們疲於開發一個接一個的需求時,很容易忘記去關注網站的效能,到了某一個節點,猛地發現,隨著越來越多程式碼的堆積,網站變得越來越慢。

本文就是從這樣的一個背景出發,著手最佳化網站的前端效能,並總結出一套開發習慣,讓我們在日常開發時,也保持高效能,而不是又一次回過頭來最佳化效能。

先來看看最佳化的成果,Lighthouse 的 Performance 評分合計提升 279%:

指標名稱最佳化前最佳化後提升
Lighthouse Performance 評分2981279%
FCP(First Contentful Paint 首次內容繪製)0.7s0.7s
LCP(Largest Contentful Paint 最大內容繪製)6.2s2.5s248%
TTI(Time to Interactive 可互動時間)10.1s2.1s480%
Speed Index(速度指數)5.6s1.8311%
TBT(Total Blocking Time 總阻塞時間)820ms120ms683%

最佳化前後對比:

最佳化前後對比

二、最佳化前

接下來就是介紹下最佳化前我們要做哪些事件:

  1. 瞭解效能指標及測量工具
  2. 分析需要最佳化的地方

1. 瞭解測量工具及效能指標

一開始我們只是感受到網站的頁面開啟時白屏時間較長,感覺效能是比較差的,那麼具體有哪些效能指標需要去關注呢?

這裡我使用的是 Chrome devtools 內建的 Lighthouse,Lighthouse 是一種開源的自動化工具,用於提高 Web 應用程式的質量。

Lighthouse 會在一系列的測試下執行網頁,比如不同尺寸的裝置和不同的網路速度。它還會檢查頁面對輔助功能指南的一致性,例如顏色對比度和 ARIA 最佳實踐。

開啟 Chrome devtools Lighthouse 即可使用。

在比較短的時間內,Lighthouse 可以給出這樣一份報告。

這份報告從 5 個方面來分析頁面: 效能、輔助功能、最佳實踐、搜尋引擎最佳化和 PWA。像效能方面,會給出一些常見的耗時統計。

最佳化前

1.1 Performance

Performance 評分統計,包括了以下指標:

1.1.1 FCP

FCP 測量在使用者導航到頁面後瀏覽器呈現第一段 DOM 內容所花費的時間。頁面上的影像、非白色<canvas>元素和 SVG 被視為 DOM 內容;不包括 iframe 內的任何內容。

1.1.2 LCP

LCP 測量視口中最大的內容元素何時呈現到螢幕上。這近似於頁面的主要內容對使用者可見的時間。

需要注意的是 LCP 的計算是一個動態的過程,如下圖最後的圖片才是這個頁面中的最大內容繪製的元素。

lcp

1.1.3 TTI

TTI 測量頁面完全互動所需的時間。

TTI 是如何計算的呢,如下圖首先沿時間軸正向搜尋時長至少為 5 秒的安靜視窗(安靜視窗是指沒有長任務且不超過兩個正在處理的網路 get 請求),然後沿時間軸反向搜尋安靜視窗之前的最後一個長任務,如果沒有找到長任務,則在 FCP 步驟停止執行,TTI 就是安靜視窗之前最後一個長任務的結束時間,如果沒有找到長任務的話,則與 FCP 值相同。

TTI

1.1.4 Speed Index

Speed Index 衡量頁面載入期間內容以視覺方式顯示的速度。Lighthouse 首先捕獲瀏覽器中頁面載入的影片,並計算幀之間的視覺進度。

1.1.5 TBT

TBT 測量頁面被阻止響應使用者輸入(例如滑鼠點選、螢幕點選或鍵盤按下)的總時間。

透過新增 First Contentful Paint 和 Time to Interactive 之間所有長任務的阻塞部分來計算總和。任何執行時間超過 50 毫秒的任務都是長任務。

50 毫秒後的時間量是阻塞部分。例如,如果 Lighthouse 檢測到一個 70 毫秒長的任務,則阻塞部分將為 20 毫秒。

如下圖淡紅色區域的時間總和就是這個頁面的 TBT 分數。

TBT

1.2 最佳實踐

用於檢測 Web 應用程式整體程式碼健康狀況,包括是否包含文件型別、圖片寬高比是否正確等等。

1.3 SEO

用於檢測搜尋引擎對網頁內容的理解程度。

2. 分析需要最佳化的地方

瞭解了關鍵的效能指標後,就可以測量看看當前網站的效能了,

上面看到綜合評分是非常低的,Lighthouse 給出了應該從哪些地方開始最佳化的建議。

2.1 Performance

效能最佳化建議主要包括以下幾點:

  • 減少未使用的 JS;
  • 合理使用圖片的格式,webp 或者 avif 更快;
  • 延遲載入不在檢視的圖片;
  • JS 壓縮;
  • 圖片的尺寸大小應該適當;
  • 減少未使用的 CSS。

效能最佳化建議

Lighthouse 診斷出的網站存在的問題:

  • 需要載入的資源太多太大,有 147 個請求,合計 11mb;
  • 有 40 個靜態資源的快取只有 1 小時
  • 滾動事件沒有新增標記{passive: true}),導致需要等待偵聽器完成執行後再滾動頁面;
  • 影像元素沒有設定明確的寬度和高度;
  • JS 檔案太多,主執行緒工作量太大、JS 執行時間太長;

存在的問題

2.2 最佳實踐

最佳實踐方面有以下問題:

  • 圖片的解析度太低,清晰度不夠;
  • 沒有設定 CSP 策略。

最佳實踐的問題

2.3 SEO

SEO 有以下問題:

  • 沒有 meta description;
  • 圖片沒有 alt 屬性;
  • robots.txt 是無效的。

SEO的問題

三、最佳化 Performance

根據上面 Lighthouse 報告,捋一捋專案中影響效能最大的因素,包括以下幾點:

  • 體積太大,達 11mb;
  • 圖片太大,圖片格式也有影響。

1. 體積最佳化

1.1 程式碼壓縮

檢查是否還有壓縮空間,或者有無工具庫未壓縮的。

1.2 程式碼分包

透過 webpack-bundle-analyzer 外掛分析包體積,將一些大的 npm 包和 runtimeChunk 獨立分包,減小包體積。

1.3 元件按需載入

React.lazy + Suspense 封裝懶載入元件,路由級元件引入懶載入元件。
同時使用骨架屏作為懶載入的兜底元件,可以讓使用者感知載入更快。
在滑鼠移入導航欄時預載入路由元件,可以加快頁面展示。

1.4 工具庫按需載入

透過 import('xx').then(xx) 按需載入工具庫。

1.5 靜態資源上傳 CDN

專案內有一些 json 檔案儲存的靜態資料,這部分檔案上傳至 CDN,改為 fetch 的方式按需引入。

1.6 刪除不需要的資源

檢查專案中引入的 mf、npm 資源,將沒有使用到的刪除。

1.7 避免重複的 npm 包引入

發現業務元件庫透過 npm 引入的原子元件庫,而專案本身又是透過 mf 引入的原子元件庫,相對於引入了 2 遍原子元件庫。

這時就需要改造業務元件庫,也改成用 mf 的方法引入。

1.8 避免 esm 依賴巢狀

因為 webpack 的按需載入是透過 import、export 來標記的,因此想要一個好的按需載入的效果,就需要避免依賴巢狀的問題。

1.9 圖示按需載入

原子元件庫 mf 暴露的方式會導致只用了 1 個 icon,就會載入元件庫下所有 icon 對應的 chunk,導致資源浪費。

新建一個 icon 的 npm 包用於 icon 的按需引入。

1.10 小結

透過以上最佳化手段,體積從 11.7mb 降低至 1.1mb,降低 10.6 倍。

最佳化前:

最佳化前

最佳化後:

最佳化後

2. 圖片最佳化

1.1 圖片懶載入

對非首屏的圖片採用圖片懶載入策略。

1.2 圖片尺寸

使用圖片時,設定圖片的合理尺寸。

1.3 圖片格式設定

優先使用 webp 格式圖片。

四、最佳化最佳實踐

1. 設定 CSP 策略

2. 設定合理的圖片的解析度

最佳化專案內的圖片解析度。

五、最佳化 SEO

1. meta description、keywords 最佳化

詳細的 meta description、keywords 可以加快 SEO。

<meta name="keywords" content="xx" /> <meta name="description" content="xx" />

2. 圖片加上 alt 屬性

<img src="smiley.gif" alt="Smiley face" />

六、最佳化前後對比

再來回顧下前後對比:

最佳化前,明顯的感知白屏時間長:

最佳化前

最佳化後,在清快取的情況下也能實現秒開:

最佳化後

整體效能提升 270%:

最佳化前後對比

七、效能監控

為了在後續的迭代過程中,保持高效能,引入內部前端監控平臺 - 燭龍,視覺化的監控前端效能。

第一步,載入 cdn 外掛:

<script
  defer
  src="https://h5static.m.jd.com/act/jd-jssdk/latest/jd-jssdk.min.js"
></script>

第二步,在入口檔案中,初始化 cdn 外掛:

useEffect(() => {
  // 初始化測速元件,在這裡可以開啟一些控制的開關,如是否上報介面
  if (IS_PROD) {
    // @ts-ignore
    jmfe.profilerInit({
      flag: xxx, // 這是應用ID,需要先在燭龍申請應用
      autoReport: true,
      autoAddStaticReport: true,
      autoAddApiReport: true,
      autoAddImageReport: false, // 支援所有圖片上報,如果圖片多,切記關閉,否則存在效能問題
      performanceReportTime: 8000,
      profilingRate: 1,
    })
  }
}, [])

第三步,檢視監控資料:

在燭龍平臺,小工具效能評分達 96分:

檢視監控資料

第四步,新增告警,實時監控

燭龍平臺支援多維度的告警服務,增加效能指標相關的告警,在效能異動時,及時發現問題,最佳化效能。

小結

本文詳細介紹了一個前端專案最佳化的詳細過程,從最佳化前的問題分析,到具體的最佳化措施,最終實現了前端效能提升了近 3 倍。同時也將效能指標落到監控平臺,實現視覺化的監控前端效能指標。

希望能對你有所幫助,感謝閱讀~

參考資料

相關文章