天天看點

H5頁面秒開優化與實踐

作者:前端圈

作者:驚墨

連結:https://juejin.cn/post/7220243380621099064

來源:稀土掘金

背景

3月份針對線上重點H5項目秒開進行治理,本文将逐漸介紹如何通過H5頁面的優化手段來提高 1.5 秒開率。

為什麼要做優化?

  • 從使用者角度看,優化能夠讓頁面加載得更快、對使用者操作響應更及時,使用者體驗更良好,提升使用者體驗和降低使用者流失率非常重要。其中 Global Web Performance Matters for ecommerce報告中也有具體說明優化的重要性。
  • 從企業角度看,優化能夠減少頁面請求數或者減小請求所占帶寬,能夠節省可觀的資源成本,最終提高收益轉化。

優化目标

H5頁面秒開優化與實踐

從上圖中可以看出,有些域名下可能低于90%,最高的也沒達到96%,離既定98%的目标還有一定差距。

H5性能分析

分析工具

  • Lighthouse
  • Chrome DevTools
  • gtmertrix 線上可視化分析工具

Webview加載H5

通常情況分以下幾個階段

  1. Webview初始化。
  2. 到達新的頁面,網絡連接配接,從伺服器下載下傳html,css,js,頁面白屏。
  3. 頁面基本架構出現,js請求頁面資料,頁面處于loading狀态。
  4. 出現所需的資料,完成整個頁面的渲染,使用者可互動。 從圖形直覺看H5 啟動過程:

如何縮短這些過程的時間,就成了優化 H5 性能的關鍵。接下來我們詳細看一下各個階段注意的優化點。

優化方案

從以下幾個方面入手:

  • 加載政策優化
  • 增加骨架屏
  • 資源請求優化(靜态資源、圖檔以及 webp 、圖檔懶加載、元件按需加載)
  • 打包資源優化
  • CDN & 緩存

接下來就逐個分析

加載政策優化

先看一張圖:

developers.google.com/web/fundame…)

H5頁面秒開優化與實踐

從這張圖裡我們能看到什麼,大緻能總結為以下四點:

  • 預設情況:HTML解析,然後加載 JS,此時 HTML 解析中斷,然後執行 JS,最後 JS執行完成并恢複 HTML解析。
  • defer情況下:HTML 和 JS 并駕齊驅,最後才執行 JS( js腳本在所有元素加載完成後執行,而且是按照js腳本聲明的順序執行,但要等到dom文檔全部解析完才會被執行)。
  • async 情況下:HTML和 JS 并駕齊驅,JS 的執行可能在 HTML解析之前就已完成了 (js腳本是亂序執行的,不管你聲明的順序如何,隻要某個js腳本加載完就立即執行)。
  • module情況下:與defer情況類似,隻不過在提取的過程中會加載多個 JS 檔案而已 (聲明acript标簽type="module"屬性進而擁抱es6的子產品導入導出文法, 加載也和defer差不多,隻不過可以加載多個JS檔案而已)。

項目中實踐示例:

H5頁面秒開優化與實踐
H5頁面秒開優化與實踐

預加載

prefetch 和 preload

preload 是一個新的 Web 标準,在頁面生命周期中提前加載你指定的資源,同時確定在浏覽器的主要渲染機制啟動之前。

具體使用如下:

<scirpt rel="preload" as="script" href="/afu_spa/activity315/assets/js/index-5a2f07e3.js" />
    
    <scirpt rel="prefetch" as="script" href="/afu_spa/activity315/assets/js/index-5a2f07e3.js" />
複制代碼           
H5頁面秒開優化與實踐
注意:preload 緊挨着 title 放,使其最早介入。

prefetch 是提示浏覽器,使用者在下次導航時可能會使用的資源(HTML,JS,CSS或者圖檔等),是以浏覽器為了提升性能可以提前加載、緩存資源。prefetch 的加載優先級相對較低,浏覽器在空閑的時候才會在背景加載。用法與 preload 類似,将 rel 的值替換成 prefetch 即可。

preload 是告訴浏覽器頁面必定需要的資源,浏覽器一定會加載這些資源,而 prefetch 是告訴浏覽器頁面可能需要的資源,浏覽器不一定會加載這些資源。是以建議:對于目前頁面很有必要的資源使用 preload,對于可能在将來的頁面中使用的資源使用 prefetch。

注意:用 preload 和 prefetch 情況下,如果資源不能被緩存,那麼都有可能浪費一部分帶寬,請慎用。非首頁的資源建議不用 preload,prefetch 作為加載下一屏資料來用。

dns-prefetch 和 preconnect

dns-prefetch

DNS 請求需要的帶寬非常小,但延遲較高,這點特别是在手機網絡上比較明顯。預讀取 DNS 能讓延遲明顯減少一些(尤其是移動網絡下)。為了幫助浏覽器對某些域名進行預解析,你可以在頁面的html标簽中添加 dns-prefetch 告訴浏覽器對指定域名預解析。

dns-prefetch 是一項使浏覽器主動去執行域名解析的功能。dns-prefetch 應該盡量的放在網頁的前面,推薦放在後面。具體使用方法如下:

<link rel="dns-prefetch" href="//*.com">
複制代碼           

洗車項目中有展現:

H5頁面秒開優化與實踐
注意:dns-prefetch需慎用,推薦首屏加載資源添加DNS Prefetch

preconnect

和 DNS prefetch 類似,preconnect 不僅會解析 DNS,還會建立 TCP 握手連接配接和 TLS 協定(如果是https的話)。用法如下:

H5頁面秒開優化與實踐

preconnect 允許浏覽器在 HTTP 請求實際發送到伺服器之前建立早期連接配接。可以預先啟動 DNS 查找、TCP 握手和 TLS 協商等連接配接,進而消除這些連接配接的往返延遲并為使用者節省時間。

<link rel="preconnect" href="//*.com.cn" />
複制代碼           

骨架屏

H5頁面秒開優化與實踐

從圖上可以看出有白屏情況,FCP 時間超過了 1秒多,解決下來就用了骨架屏來解決白屏情況 并提升 FCP。

骨架屏就是在頁面資源尚未加載完成以及渲染尚未完成時,需要先給使用者的展示頁面大緻結構。直到資源加載完成以及渲染完成後,使用渲染的頁面。骨架屏處理方案也很多,常用方案有以下幾種:

  • 首屏:可以在index.html模版中手寫骨架屏相關代碼。
  • 其他頁面:可以利用UI提供SVG圖
  • 作為SPA中路由切換的loading:需自己編寫骨架屏,推薦兩個成熟友善定制的svg元件去定制骨架屏- react-content-loader和vue-content-loader。
  • 骨架圖渲染前不要出現任何網絡請求,在此之前 HTML 内容不要超過 4KB。

我這裡采用了固定的骨架屏SVG打包自動注入到模闆方式。并産出了基于vite 的自動化注入骨架屏和無阻塞緩存資源檔案@auto/vite-plugin-cdn私有插件。

舉個:

H5頁面秒開優化與實踐
H5頁面秒開優化與實踐

資源請求優化

圖檔壓縮和webp

圖檔是網站性能優化需要重點關注的方向。為什麼這麼說呢?來看個圖檔:

H5頁面秒開優化與實踐

一般 UI 提供的切圖都是未通過壓縮的圖檔,所有在開發過程中,我們必須再壓縮一次。如果壓縮後的圖檔還是大于 500KB 就要考慮将圖檔分割成多張。 目前市面上圖檔壓縮比較多,給大家推薦個好用的工具(docsmall)。可批量壓縮各類圖檔。

H5頁面秒開優化與實踐

WebP 的優勢展現在它具有更優的圖像資料壓縮算法,在肉眼識别無差異的圖像品質情況下帶來更小的圖檔體積的優勢;同時具備了無損和有損的壓縮模式、Alpha 透明以及動畫的特性,在 JPEG 和 PNG 上的轉化效果都相當優秀、穩定和統一。内部提供了圖檔資源可以上傳到 前端加速服務 或 前端靜态資源服務内部資源庫會自動生成webp格式,可以在項目打包的時候處理圖檔時加上 format=webp 即可,接口動态圖檔可采用 @auto/img-crop私有包做裁切同時也可通過參數動态支援webp和設定緩存時間。

webp前後對比:

H5頁面秒開優化與實踐
H5頁面秒開優化與實踐

從對比結果看,同圖檔采用webp 大小至少減少了 50%,越大的圖優化比例越大。大幅減少了檔案體積,縮短了加載的時間,大頁面圖檔量較多的場景下,頁面的渲染速度是有較大提升的。

CDN & 緩存

上面提到了前端加速服務 或 前端靜态資源服務内部服務均內建CDN功能。具體情況可以參考使用文檔。

結合以上兩個服務的應用能很好的處理資源問題,目前我們的新 SPA項目都釋出到了前端加速服務上。如圖:

H5頁面秒開優化與實踐

資源檔案自動都有緩存

未覆寫的 CDN

H5頁面秒開優化與實踐
H5頁面秒開優化與實踐

從圖上看左圖沒命中緩存,右圖則命中緩存,很多項目由于域名接口和網頁接口一樣CDN 就是沒開啟緩存,我們後通過域名Path 來針對開啟 CDN緩存。

打包資源優化

提取第三方庫

通常情況下,大多第三方庫的代碼不做版本更新是不會發生變化的 ,這時就可以用到 DllPlugin:把複用性較高的第三方庫打包在一起,不更新就不需要重新打包。

這樣做的優點:

  • 提取的第三方庫生成的資源版本号(資源的通路連接配接)不會變,提高了緩存的利用;
  • 避免打包出單個檔案的大小太大,不利于加載;
  • 每次建構隻重新打包業務代碼,提高打包效率。

為了讓前端頁面性能更優, App WebView 中針對 React、Vue、Zepto 三大常用架構相關資源及 Polyfill 進行了預加載處理,是以我們把這些固定的資源調整為無阻塞的預加載位址。具體如何使用 App H5提供了 webpack的相關配置說明。

這裡針對 vite 的配置做些說明:

import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';
import legacy from '@vitejs/plugin-legacy';
import createExternal from 'rollup-plugin-external-globals';
import cdn from '@auto/vite-plugin-cdn'; 
export default ({ mode }) => {
  process.env = { ...process.env, ...loadEnv(mode, process.cwd()) };
  const { VITE_USER_NODE_ENV = 'mock' } = process.env;
  const plugins: Array<any> = [];
  const isProduction = process.env.NODE_ENV === 'production';
  if (isProduction) {
    // 設定預加載的 react 等包為 external
    plugins.push(
      createExternal({
        react: 'React',
        'react-dom': 'ReactDOM',
        history: 'HistoryLibrary',
        'react-router': 'ReactRouter',
        'react-router-dom': 'ReactRouterDOM',
        immer: 'immer',
        axios: 'axios',
        'js-cookie': 'Cookies',
      }),
    );
    plugins.push(
      cdn({
        enableModule: true,
      }),
    );
  }
  // https://vitejs.dev/config/
  return defineConfig({
      legacy({
        targets: ['> 0.05%', 'not dead', 'not op_mini all'],
      }),
      ...plugins,
    ],

    build: {
      rollupOptions: {
        external: [
          'react',
          'react-dom',
          'history',
          'react-router',
          'react-router-dom',
          'axios',
          'js-cookie',
        ],
       
      },
    },
  });
};
複制代碼           

這裡@auto/vite-plugin-cdn私有插件中提供正常骨架屏、預加載資源、處理資源加載順序

示例:

H5頁面秒開優化與實踐
H5頁面秒開優化與實踐

優化打包資源

我們來看一組圖:

H5頁面秒開優化與實踐
H5頁面秒開優化與實踐

從圖上看優化前後,檔案數從295 個減少到 214 個, 大小從 1.63MB 減少到439.88KB,大小降了73.6460%

webpack 和 vite 配置

設定預警來檢驗打封包件

資源(asset)是從 webpack 生成的任何檔案。此選項根據單個資源體積(機關: bytes),控制 webpack 何時生成 性能提示。 用法:

//  webpack 設定單個靜态資源檔案的大小最大超過300KB則會給出警告
module.exports = {
  //...
  performance: {
    maxAssetSize: 1024 * 300 
  }
};
複制代碼           
// vite 設定
build: {
      chunkSizeWarningLimit: 300 // 塊大小警告的限制(以 kbs 為機關)預設 500
    }
複制代碼           

将打包後的靜态資源控制在 300KB 以内,最終通過 Gzip 壓縮後,基本都在 100KB 以内。其他的優化包括提取第三方庫、移除調試和無用代碼、Tree Shaking 等。

總結

經過以上的一系列的優化實施,我們來看一下優化前後資料的對比:

H5頁面秒開優化與實踐

從2月底開始實施優化,上圖可以很明顯看出資料的變化,秒開率雖然已經做到了95%以上,達到 98%的隻有個别項目,還需要在疊代過程中關注性能以及持續的優化,這裡也感謝為H5頁面秒開做出貢獻的同學。如有什麼問題和想法歡迎留言區評論交流。

繼續閱讀