<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          騰訊企鵝輔導(dǎo) H5 性能極致優(yōu)化總結(jié)

          共 11313字,需瀏覽 23分鐘

           ·

          2021-09-23 04:03

          企鵝輔導(dǎo) H5 頁(yè)面在長(zhǎng)期迭代過(guò)程中,逐漸累積了一些性能問(wèn)題,導(dǎo)致頁(yè)面加載、渲染速度變慢。為了提升用戶體驗(yàn),近期針對(duì)頁(yè)面加載速度,渲染速度做了專項(xiàng)優(yōu)化,本文是對(duì)此次優(yōu)化的實(shí)踐總結(jié)。分析過(guò)程比較細(xì)致,希望能給性能分析經(jīng)驗(yàn)欠缺的同學(xué)一些幫助。

           大廠技術(shù)  高級(jí)前端  Node進(jìn)階

          點(diǎn)擊上方 程序員成長(zhǎng)指北,關(guān)注公眾號(hào)

          回復(fù)1,加入高級(jí)Node交流群

          項(xiàng)目背景

          H5 項(xiàng)目是企鵝輔導(dǎo)的核心項(xiàng)目,已迭代四年多,包括了課程詳情頁(yè)/老師詳情頁(yè)/報(bào)名頁(yè)/支付頁(yè)面等頁(yè)面,構(gòu)建產(chǎn)物用于企鵝輔導(dǎo) APP/H5(微信/QQ/瀏覽器),迭代過(guò)程中了也累積了一些性能問(wèn)題導(dǎo)致頁(yè)面加載、渲染速度變慢,為了提升用戶體驗(yàn),近期啟動(dòng)了 “H5 性能優(yōu)化” 項(xiàng)目,針對(duì)頁(yè)面加載速度,渲染速度做了專項(xiàng)優(yōu)化,下面是對(duì)本次優(yōu)化的總結(jié),包括以下幾部分內(nèi)容:

          1. 性能優(yōu)化效果展示

          2. 性能指標(biāo)及數(shù)據(jù)采集

          3. 性能分析方法及環(huán)境準(zhǔn)備

          4. 性能優(yōu)化具體實(shí)踐

          一、性能指標(biāo)及數(shù)據(jù)采集

          企鵝輔導(dǎo) H5 采用的性能指標(biāo)包括:

          1. 頁(yè)面加載時(shí)間 —— 頁(yè)面以多快的速度加載和渲染元素到頁(yè)面上,具體如下:

          • First contentful paint (FCP):測(cè)量頁(yè)面開(kāi)始加載到某一塊內(nèi)容顯示在頁(yè)面上的時(shí)間。

          • Largest contentful paint (LCP):測(cè)量頁(yè)面開(kāi)始加載到最大文本塊內(nèi)容或圖片顯示在頁(yè)面中的時(shí)間。

          • DomContentLoaded Event:DOM 解析完成時(shí)間。

          • OnLoad Event:頁(yè)面資源加載完成時(shí)間。

          2. 加載后響應(yīng)時(shí)間 —— 頁(yè)面加載和執(zhí)行js代碼后多久能響應(yīng)用戶交互。

          • First input delay (FID):測(cè)量用戶首次與網(wǎng)站進(jìn)行交互(例如點(diǎn)擊一個(gè)鏈接、按鈕、js自定義控件)到瀏覽器真正進(jìn)行響應(yīng)的時(shí)間。

          3. 視覺(jué)穩(wěn)定性 —— 頁(yè)面元素是否會(huì)以用戶不期望的方式移動(dòng),并干擾用戶的交互。

          • Cumulative layout shift (CLS):測(cè)量從頁(yè)面開(kāi)始加載到狀態(tài)變?yōu)殡[藏過(guò)程中,發(fā)生不可預(yù)期的 layout shifts 的累積分?jǐn)?shù)。

          項(xiàng)目使用了 IMLOG 進(jìn)行數(shù)據(jù)上報(bào),ELK 體系進(jìn)行現(xiàn)網(wǎng)數(shù)據(jù)監(jiān)控,Grafana 配置視圖,觀察現(xiàn)網(wǎng)情況。

          根據(jù)指標(biāo)的數(shù)據(jù)分布,能及時(shí)發(fā)現(xiàn)頁(yè)面數(shù)據(jù)異常采取措施。

          二、性能分析及環(huán)境準(zhǔn)備

          現(xiàn)網(wǎng)頁(yè)面情況:

          可以看到進(jìn)度條在頁(yè)面已經(jīng)展示后還在持續(xù) loading,加載時(shí)間長(zhǎng)達(dá)十幾秒,比較影響了用戶體驗(yàn)。

          根據(jù) Google 開(kāi)發(fā)文檔 對(duì)瀏覽器架構(gòu)的解釋:

          當(dāng)導(dǎo)航提交完成后,渲染進(jìn)程開(kāi)始著手加載資源以及渲染頁(yè)面。一旦渲染進(jìn)程“完成”(finished)渲染,它會(huì)通過(guò) IPC 告知瀏覽器進(jìn)程(注意這發(fā)生在頁(yè)面上所有幀(frames) 的 onload 事件都已經(jīng)被觸發(fā)了而且對(duì)應(yīng)的處理函數(shù)已經(jīng)執(zhí)行完成了的時(shí)候),然后 UI 線程就會(huì)停止導(dǎo)航欄上旋轉(zhuǎn)的圈圈。

          我們可以知道,進(jìn)度條的加載時(shí)長(zhǎng)和 onload 時(shí)間密切相關(guān),要想進(jìn)度條盡快結(jié)束就要減少 onload 時(shí)長(zhǎng)。

          根據(jù)現(xiàn)狀,使用 ChromeDevTool 作為基礎(chǔ)的性能分析工具,觀察頁(yè)面性能情況:

          • Network:觀察網(wǎng)絡(luò)資源加載耗時(shí)及順序

          • Performace:觀察頁(yè)面渲染表現(xiàn)及JS執(zhí)行情況

          • Lighthouse:對(duì)網(wǎng)站進(jìn)行整體評(píng)分,找出可優(yōu)化項(xiàng)

          下面以企鵝輔導(dǎo)課程詳情頁(yè)為案例進(jìn)行分析,找出潛在的優(yōu)化項(xiàng)。

          (注意使用 Chrome 隱身窗口并禁用插件,移除其他加載項(xiàng)對(duì)頁(yè)面的影響。)

          1. Network 分析

          通常進(jìn)行網(wǎng)絡(luò)分析需要禁用緩存、啟用網(wǎng)絡(luò)限速(4g / 3g) 模擬移動(dòng)端弱網(wǎng)情況下的加載情況,因?yàn)?wifi 網(wǎng)絡(luò)可能會(huì)抹平性能差距。

          可以看到 DOMContentLoaded 的時(shí)間在 6.03s ,但 onload 的時(shí)間卻在 20.92s。

          先觀察 DOMContentLoaded 階段,發(fā)現(xiàn)最長(zhǎng)請(qǐng)求路徑在 vendor.js ,JS大小為 170kB,花費(fèi)時(shí)間為 4.32s。

          繼續(xù)觀察 DOMContentLoaded 到 onload 的這段時(shí)間:


          可以發(fā)現(xiàn) onload 事件被大量媒體資源阻塞了,關(guān)于 onload 事件的影響因素,可以參考這篇文章

          結(jié)論是瀏覽器認(rèn)為資源完全加載完成(HTML解析的資源和動(dòng)態(tài)加載的資源)才會(huì)觸發(fā) onload。

          結(jié)合上圖可以發(fā)現(xiàn)加載了圖片、視頻、iframe 等資源,阻塞了 onload 事件的觸發(fā)。

          Network 總結(jié)

          1. DOM 的解析受 JS 加載和執(zhí)行的影響,盡量對(duì) JS 進(jìn)行壓縮、拆分處理(HTTP2環(huán)境下),能減少 DOMContentLoaded 時(shí)間。

          2. 圖片、視頻、iframe 等資源,會(huì)阻塞 onload 事件的觸發(fā),需要優(yōu)化資源的加載時(shí)機(jī),盡快觸發(fā) onload。


          2. Performance 分析

          使用 Performance 模擬移動(dòng)端注意手機(jī)處理器能力比 PC 差,所以一般將 CPU 設(shè)置為 4x slowdown 或 6x slowdown 進(jìn)行模擬。


          觀察幾個(gè)核心的數(shù)據(jù):

          1. Web Vitals ( FP / FCP / LCP / Layout Shift ) 核心頁(yè)面指標(biāo) 和 Timings 時(shí)長(zhǎng)

          可以看到 LCP、DCL和 Onload Event 時(shí)間較長(zhǎng),且出現(xiàn)了多次 Layout Shift。

          要 LCP 盡量早觸發(fā),需要減少頁(yè)面大塊元素的渲染時(shí)間,觀察 Frames 或ScreenShots 的截圖,關(guān)注頁(yè)面的元素渲染情況。

          可以通過(guò)在 Experience 行點(diǎn)擊Layout Shift ,在 Summary 面板找到具體的偏移內(nèi)容。


          1. Main Long Tasks 長(zhǎng)任務(wù)數(shù)量和時(shí)長(zhǎng)

          可以看到頁(yè)面有大量的 Long Tasks 需要進(jìn)行優(yōu)化,其中 couse.js (頁(yè)面代碼)的解析執(zhí)行時(shí)間長(zhǎng)達(dá) 800ms。

          處理 Long Tasks,可以在開(kāi)發(fā)環(huán)境進(jìn)行錄制,這樣在 Main Timeline 能看到具體的代碼執(zhí)行文件和消耗時(shí)長(zhǎng)。

          Performance 總結(jié)

          1. 頁(yè)面 LCP 觸發(fā)時(shí)間較晚,且出現(xiàn)多次布局偏移,影響用戶體驗(yàn),需要盡早渲染內(nèi)容和減少布局偏移。

          2. 頁(yè)面 Long Tasks 較多,需要對(duì) JS 進(jìn)行合理拆分和加載,減少 Long Tasks 數(shù)量,特別是 影響 DCL 和 Onload Event 的 Task。


          3. Lighthouse 分析

          使用 ChromeDevTool 內(nèi)置 lighthouse 對(duì)頁(yè)面進(jìn)行跑分:

          分?jǐn)?shù)較低,可以看到 Metrics 給出了核心的數(shù)據(jù)指標(biāo),這邊顯示的是 TTI SI TBT 不合格,LCP 需要提升,F(xiàn)CP 和 CLS 達(dá)到了良好的標(biāo)準(zhǔn),可以查看分?jǐn)?shù)計(jì)算標(biāo)準(zhǔn)

          同時(shí) Lighthouse 會(huì)提供一些優(yōu)化建議,在 Oppotunities 和 Diagnostics 項(xiàng),能看到具體的操作指南,如圖片大小、移除無(wú)用 JS 等,可以根據(jù)指南進(jìn)行項(xiàng)目的優(yōu)化。

          Lighthouse 的評(píng)分內(nèi)容是根據(jù)項(xiàng)目整體加載項(xiàng)目進(jìn)行打分的,審查出的問(wèn)題同樣包含 Network、Performance 的內(nèi)容,所以也可以看作是對(duì) Network、Performance 問(wèn)題的優(yōu)化建議。

          Lighthouse 總結(jié)

          1. 根據(jù)評(píng)分,可以看出 TTI、SI、TBT、LCP這四項(xiàng)指標(biāo)需要提高,可以參考lighthouse 文檔進(jìn)行優(yōu)化。

          2. Oppotunities 和 Diagnostics 提供了具體的優(yōu)化建議,可以參考進(jìn)行改善。


          4. 環(huán)境準(zhǔn)備

          剛才是對(duì)線上網(wǎng)頁(yè)進(jìn)行初步的問(wèn)題分析,要實(shí)際進(jìn)行優(yōu)化和觀察,需要進(jìn)行環(huán)境的模擬,讓優(yōu)化效果能更真實(shí)在測(cè)試環(huán)境中體現(xiàn)。

          代理使用:whistle、charles、fiddler 等。

          本地環(huán)境、測(cè)試環(huán)境模擬:nginx、nohost、stke 等。

          數(shù)據(jù)上報(bào):IMLOG、TAM、RUM 等(這三個(gè)工具均為團(tuán)隊(duì)內(nèi)部的日志上報(bào)工具,類似業(yè)界 log4js、sentry)。

          前端代碼打包分析:webpack-bundle-analyzer 、rollup-plugin-visualizer 等。

          分析問(wèn)題時(shí)使用本地代碼,本地模擬線上環(huán)境驗(yàn)證優(yōu)化效果,最后再部署到測(cè)試環(huán)境驗(yàn)證,提高開(kāi)發(fā)效率。


          三、性能優(yōu)化具體實(shí)踐

          PART1: 加載時(shí)間優(yōu)化

          Network 中對(duì)頁(yè)面中加載的資源進(jìn)行分類:

          第一部分是影響 DOM 解析的 JS 資源,可以看到這里分類為關(guān)鍵 JS 和非關(guān)鍵 JS,是根據(jù)是否參與首面渲染劃分的。

          這里的非關(guān)鍵 JS 我們可以考慮延遲異步加載,關(guān)鍵 JS 進(jìn)行拆分優(yōu)化處理。


          1. 關(guān)鍵 JS 打包優(yōu)化

          JS 文件數(shù)量8個(gè),總體積 460.8kB,最大文件 170KB


          1.1 Splitchunks 的正確配置

          vendor.js 170kB(gzipd) 是所有頁(yè)面都會(huì)加載的公共文件,打包規(guī)則是 miniChunks: 3,引用超過(guò)3次的模塊將被打進(jìn)這個(gè)js。

          分析vendor.js的具體構(gòu)成(上圖)

          以 string-strip-html.umd.js 為例 大小為34.7KB,占了 vendor.js 的 20%體積,但只有一個(gè)頁(yè)面多次使用到了這個(gè)包,觸發(fā)了 miniChunks 的規(guī)則,被打進(jìn)了 vendor.js。

          同理對(duì) vendor.js 的其他模塊進(jìn)行分析,iosSelect.js、howler.js、weixin-js-sdk 等模塊都只有 3、4 個(gè)頁(yè)面/組件依賴,但也同樣打進(jìn)了 vendor.js。

          由上面的分析,我們可以得出結(jié)論:不能簡(jiǎn)單的依靠 miniChunks 規(guī)則對(duì)頁(yè)面依賴模塊進(jìn)行抽離打包,要根據(jù)具體情況拆分公共依賴。

          修改后的 vendor 根據(jù)業(yè)務(wù)具體的需求,提取不同頁(yè)面和組件都有的共同依賴(imutils/imlog/qqapi)。

          vendor: {
          test({ resource }) {
          return/[\\/]node_modules[\\/](@tencent\/imutils|imlog\/)|qqapi/.test(resource);
          },
          name: 'vendor',
          priority: 50,
          minChunks: 1,
          reuseExistingChunk: true,
          },

          而其他未指定的公共依賴,新增一個(gè) common.js,將閾值調(diào)高到 20 或更高(當(dāng)前頁(yè)面數(shù)76),讓公共依賴成為大多數(shù)頁(yè)面的依賴,提高依賴緩存利用率,調(diào)整完后,vendor.js 的大小減少到 30KB,common.js 大小為 42KB。

          兩個(gè)文件加起來(lái)大小為 72KB,相對(duì)于優(yōu)化前體積減少了 60%(100KB)。


          1.2 公共組件的按需加載

          course.js 101kB (gzipd) 這個(gè)文件是頁(yè)面業(yè)務(wù)代碼的文件:

          觀察上圖,基本都是業(yè)務(wù)代碼,除了一個(gè)巨大的 component Icon,占了 25k,頁(yè)面文件1/4的體積,但在代碼中使用到的 Icon 總共才8個(gè)。

          分析代碼,可以看到這里使用 require 加載 svg,Webpack 將 require 文件夾內(nèi)的內(nèi)容一并打包,導(dǎo)致頁(yè)面 Icon 組件冗余。

          如何解決這類問(wèn)題實(shí)現(xiàn)按需加載?

          按需加載的內(nèi)容應(yīng)該為獨(dú)立的組件,我們將之前的單一入口的 Icon 組件(動(dòng)態(tài) dangerouslySetInnerHTML)改成單文件組件模式直接引入使用圖標(biāo)。

          但實(shí)際開(kāi)發(fā)中這樣會(huì)有些麻煩,一般需要統(tǒng)一的 import 路徑,指定需要的圖標(biāo)再加載,參考 babel-plugin-import,我們可以配置 babel 的依賴加載路徑調(diào)整 Icon 的引入方式,這樣就實(shí)現(xiàn)了圖標(biāo)的按需加載。

          按需加載后,重新編譯,查看打包帶來(lái)的收益,頁(yè)面的 Icons 組件 stat size 由 74KB 降到了 20KB,體積減少了 70%。


          1.3 業(yè)務(wù)組件的代碼拆分 (Code Splitting)

          觀察頁(yè)面,可以看到”課程大綱“、”課程詳情“、”購(gòu)課須知“這三個(gè)模塊并不在頁(yè)面的首屏渲染內(nèi)容里:

          我們可以考慮對(duì)頁(yè)面這幾部分組件進(jìn)行拆分再延遲加載,減少業(yè)務(wù)代碼 JS 大小和執(zhí)行時(shí)長(zhǎng)。

          拆分的方式很多,可以使用 react-loadable、@loadable/component 等庫(kù)實(shí)現(xiàn),也可以使用React 官方提供的 React.lazy。

          拆分后的代碼:

          代碼拆分會(huì)導(dǎo)致組件會(huì)有渲染的延遲,所以在項(xiàng)目中使用應(yīng)該綜合用戶體驗(yàn)和性能再做決定,通過(guò)拆分也能使部分資源延后加載優(yōu)化加載時(shí)間。

          1.4 Tree Shaking 優(yōu)化

          項(xiàng)目中使用了 TreeShaking 的優(yōu)化,用時(shí)候要注意 sideEffects 的使用場(chǎng)景,以免打包產(chǎn)物和開(kāi)發(fā)不一致。

          經(jīng)過(guò)上述優(yōu)化步驟,整體打包內(nèi)容:

          JS 文件數(shù)量6個(gè),總體積 308KB,最大文件體積 109KB

          關(guān)鍵 JS 優(yōu)化數(shù)據(jù)對(duì)比:


          文件總體積 最大文件體積
          優(yōu)化前 460.8 kb 170 kb
          優(yōu)化后 308 kb 109 kb
          優(yōu)化效果 總體積減少 50% 最大文件體積減少 56%


          2.非關(guān)鍵 JS 延遲加載

          頁(yè)面中包含了一些上報(bào)相關(guān)的 JS 如 sentry,beacon(燈塔 SDK)等,對(duì)于這類資源,如果在弱網(wǎng)情況,可能會(huì)成為影響 DOM 解析的因素。

          為了減少這類非關(guān)鍵 JS 的影響,可以在頁(yè)面完成加載后再加載非關(guān)鍵 JS,如 sentry 官方也提供了延遲加載的方案

          在項(xiàng)目中還發(fā)現(xiàn)了一部分非關(guān)鍵 JS,如驗(yàn)證碼組件,為了在下一個(gè)頁(yè)面中能利用緩存盡快加載,所以在上一個(gè)頁(yè)面提前加載一次生成緩存。

          如果不訪問(wèn)下一個(gè)頁(yè)面,可以認(rèn)為這是一次無(wú)效加載,這類的提前緩存方案反而會(huì)影響到頁(yè)面性能。

          針對(duì)這里資源,我們可以使用 Resource Hints,針對(duì)資源做 Prefetch 處理。

          檢測(cè)瀏覽器是否支持 Prefech,支持的情況下我們可以創(chuàng)建 Prefetch 鏈接,不支持就使用舊邏輯直接加載,這樣能更大程度保證頁(yè)面性能,為下一個(gè)頁(yè)面提供提前加載的支持。

          const isPrefetchSupported = () => {
          const link = document.createElement('link');
          const { relList } = link;

          if (!relList || !relList.supports) {
          returnfalse;
          }
          return relList.supports('prefetch');
          };
          const prefetch = () => {
          const isPrefetchSupport = isPrefetchSupported();
          if (isPrefetchSupport) {
          const link = document.createElement('link');
          link.rel = 'prefetch';
          link.as = type;
          link.href = url;
          document.head.appendChild(link);
          } elseif (type === 'script') {
          // load script
          }
          };

          優(yōu)化效果:非關(guān)鍵JS不影響頁(yè)面加載


          3.媒體資源加載優(yōu)化

          3.1 加載時(shí)序優(yōu)化

          可以觀察到 onload 被大量的圖片資源和視頻資源阻塞了,但是頁(yè)面上并沒(méi)有展示對(duì)應(yīng)的圖片或視頻,這部分內(nèi)容應(yīng)該進(jìn)行懶加載處理。

          處理方式主要是要控制好圖片懶加載的邏輯(如 onload 后再加載),可以借助各類 lazyload 的庫(kù)去實(shí)現(xiàn)。H5項(xiàng)目用的是位置檢測(cè)(getBoundingClientRect )圖片到達(dá)頁(yè)面可視區(qū)域再展示。

          但要注意懶加載不能阻塞業(yè)務(wù)的正常展示,應(yīng)該做好超時(shí)處理、重試等兜底措施。

          3.2 大小尺寸優(yōu)化

          課程詳情頁(yè) 每張?jiān)斍閳D的寬為 1715px,以 6s 為基準(zhǔn)(375px)已經(jīng)是 4x 圖了,大圖片在弱網(wǎng)情況下會(huì)影響頁(yè)面加載和渲染速度。


          使用 CDN 圖床尺寸大小壓縮功能,根據(jù)不同的設(shè)備渲染不同大小的圖片調(diào)整圖片格式,根據(jù)網(wǎng)絡(luò)情況,渲染不同清晰度的圖。



          可以看到在弱網(wǎng)(移動(dòng) 3G 網(wǎng)絡(luò))的情況下,同一張圖片不同尺寸加載速度最高和最低相差接近 6 倍,給用戶的體驗(yàn)截然不同。

          CDN 配合業(yè)務(wù)具體實(shí)現(xiàn):使用 img 標(biāo)簽 srcset/sizes 屬性和 picutre 標(biāo)簽實(shí)現(xiàn)響應(yīng)式圖片,具體可參考文檔

          使用 URL 動(dòng)態(tài)拼接方式構(gòu)造 URL 請(qǐng)求,根據(jù)機(jī)型寬度和網(wǎng)絡(luò)情況,判斷當(dāng)前圖片寬度倍數(shù)進(jìn)行調(diào)整(如 iPhone 1x,iPad 2x,弱網(wǎng) 0.5x)。

          優(yōu)化效果:移動(dòng)端 正常網(wǎng)絡(luò)情況下圖片體積減小 220%、弱網(wǎng)情況下圖片體積減小 13 倍。

          注意實(shí)際業(yè)務(wù)中需要視覺(jué)同學(xué)參與,評(píng)估圖片的清晰度是否符合視覺(jué)標(biāo)準(zhǔn),避免反向優(yōu)化!

          3.3 其他類型資源優(yōu)化

          iframe

          加載 iframe 有可能會(huì)對(duì)頁(yè)面的加載產(chǎn)生嚴(yán)重的影響,在 onload 之前加載會(huì)阻塞 onload 事件觸發(fā),從而阻塞 loading,但是還存在另一個(gè)問(wèn)題。

          如下圖所示,頁(yè)面在已經(jīng) onload 的情況下觸發(fā) iframe 的加載,進(jìn)度條仍然在不停的轉(zhuǎn)動(dòng),直到 iframe 的內(nèi)容加載完成。


          可以將 iframe 的時(shí)機(jī)放在 onload 之后,并使用 setTimeout 觸發(fā)異步加載 iframe,可避免 iframe 帶來(lái)的 loading 影響。

          數(shù)據(jù)上報(bào)

          項(xiàng)目中使用 image 的數(shù)據(jù)上報(bào)請(qǐng)求,在正常網(wǎng)絡(luò)情況下可能感受不到對(duì)頁(yè)面性能的影響。

          但在一些特殊情況,如其中一個(gè)圖片請(qǐng)求的耗時(shí)特別長(zhǎng)就會(huì)阻塞頁(yè)面 onload 事件的觸發(fā),延長(zhǎng) loading 時(shí)間。

          解決上報(bào)對(duì)性能的影響問(wèn)題有以下方案:

          1. 延遲合并上報(bào)

          2. 使用 Beacon API

          3. 使用 post 上報(bào)

          H5項(xiàng)目采用了延遲合并上報(bào)的方案,業(yè)務(wù)可根據(jù)實(shí)際需要進(jìn)行選擇。

          優(yōu)化效果:全部數(shù)據(jù)上報(bào)在 onload 后處理,避免對(duì)性能產(chǎn)生影響。

          字體優(yōu)化

          項(xiàng)目中可能會(huì)包含很多視覺(jué)指定渲染的字體,當(dāng)字體文件比較大的時(shí)候,也會(huì)影響到頁(yè)面的加載和渲染,可以使用 fontmin 將字體資源進(jìn)行壓縮,生成精簡(jiǎn)版的字體文件。

          優(yōu)化前:20kB => 優(yōu)化后:14kB:


          PART2: 頁(yè)面渲染優(yōu)化

          1. 直出頁(yè)面 TTFB 時(shí)間優(yōu)化

          名詞解釋:

          NGW:內(nèi)部網(wǎng)關(guān),基于 Node.js。

          STKE:公司內(nèi)部 TKE。

          目前我們?cè)?STKE 部署了直出服務(wù),通過(guò)監(jiān)控發(fā)現(xiàn)直出平均耗時(shí)在 300+ms。

          TTFB 時(shí)間在 100 ~ 200 之間波動(dòng),影響了直出頁(yè)面的渲染。

          通過(guò)日志打點(diǎn)、查看 Nginx Accesslog 日志、網(wǎng)關(guān)監(jiān)控耗時(shí),得出以下數(shù)據(jù)(如圖)

          • STKE 直出程序耗時(shí)是 20ms 左右

          • 直出網(wǎng)關(guān) NGW -> STKE 耗時(shí) 60ms 左右

          • 反向代理網(wǎng)關(guān) Nginx -> NGW 耗時(shí) 60ms 左右

          登錄 所在機(jī)器,ping STKE 機(jī)器,有以下數(shù)據(jù)

          平均時(shí)延在 32ms,tcp 三次握手+返回?cái)?shù)據(jù)(最后一次 ack 時(shí)發(fā)送數(shù)據(jù))= 2個(gè) rtt,約 64ms,和日志記錄的數(shù)據(jù)一致

          查看 NGW 機(jī)器所在區(qū)域?yàn)樘旖颍琒TKE 機(jī)器所在區(qū)域?yàn)槟暇梢猿醪脚袛嗍怯蓹C(jī)房物理距離導(dǎo)致的網(wǎng)絡(luò)時(shí)延,如下圖所示:

          切換 NGW 到南京機(jī)器 ping STKE 南京的機(jī)器,有以下數(shù)據(jù):

          同區(qū)域機(jī)器 ping 的網(wǎng)絡(luò)時(shí)延只有 0.x毫秒,如下圖所示:

          綜合上述分析,直出頁(yè)面TTFB時(shí)間過(guò)長(zhǎng)的根本原因是:NGW 網(wǎng)關(guān)部署和 Nginx、STKE 不在同一區(qū)域,導(dǎo)致網(wǎng)絡(luò)時(shí)延的產(chǎn)生。

          解決方案是讓網(wǎng)關(guān)和直出服務(wù)機(jī)房部署在同一區(qū)域,執(zhí)行了以下操作:

          • NGW擴(kuò)容

          • 北極星開(kāi)啟就近訪問(wèn)

          優(yōu)化前:

          優(yōu)化后:

          優(yōu)化效果如上圖:


          七天網(wǎng)關(guān)平均耗時(shí)
          優(yōu)化前 153 ms
          優(yōu)化后 31 ms 優(yōu)化 80%(120 ms)


          2. 頁(yè)面渲染時(shí)間優(yōu)化

          模擬弱網(wǎng)情況(slow 3g)Performance 錄制頁(yè)面渲染情況,從下圖 Screenshot 中可以發(fā)現(xiàn):

          1. DOM 開(kāi)始解析,但頁(yè)面還未渲染

          2. CSS 文件下載完成后頁(yè)面才正常渲染

          CSS 不會(huì)阻塞頁(yè)面解析,但會(huì)阻塞頁(yè)面渲染,如果 CSS 文件較大或弱網(wǎng)情況,會(huì)影響到頁(yè)面渲染時(shí)間,影響用戶體驗(yàn)。

          借助 ChromeDevTool 的 Coverage 工具(More Tools 里面),錄制頁(yè)面渲染時(shí) CSS 的使用率:

          發(fā)現(xiàn)首屏的 CSS 使用率才 15%,可以考慮對(duì)頁(yè)面首屏的關(guān)鍵 CSS 進(jìn)行內(nèi)聯(lián)讓頁(yè)面渲染不被CSS 阻塞,再把完整 CSS 加載進(jìn)來(lái)。

          實(shí)現(xiàn) Critial CSS 的優(yōu)化可以考慮使用 critters

          優(yōu)化后效果:

          CSS 資源正在下載時(shí),頁(yè)面已經(jīng)能正常渲染顯示了,對(duì)比優(yōu)化前,渲染時(shí)間上提升了 1~2 個(gè) CSS 文件加載的時(shí)間。

          3. 頁(yè)面布局抖動(dòng)優(yōu)化

          觀察頁(yè)面的元素變化:


          優(yōu)化前(左圖):圖標(biāo)缺失、背景圖缺失、字體大小改變導(dǎo)致頁(yè)面抖動(dòng)、出現(xiàn)非預(yù)期頁(yè)面元素導(dǎo)致頁(yè)面抖動(dòng)。

          優(yōu)化后:內(nèi)容相對(duì)固定, 頁(yè)面元素出現(xiàn)無(wú)突兀感。

          主要優(yōu)化內(nèi)容:

          1. 確定直出頁(yè)面元素出現(xiàn)位置,根據(jù)直出數(shù)據(jù)做好布局

          2. 頁(yè)面小圖可以通過(guò) base64 處理,頁(yè)面解析的時(shí)候就會(huì)立即展示

          3. 減少動(dòng)態(tài)內(nèi)容對(duì)頁(yè)面布局的影響,使用脫離文檔流的方式或定好寬高


          四、性能優(yōu)化效果展示

          優(yōu)化效果由以下指標(biāo)量化:

          • 首次內(nèi)容繪制時(shí)間FCP(First Contentful Paint):標(biāo)記瀏覽器渲染來(lái)自 DOM 第一位內(nèi)容的時(shí)間點(diǎn)。

          • 視窗最大內(nèi)容渲染時(shí)間LCP(Largest Contentful Paint):代表頁(yè)面可視區(qū)域接近完整渲染。

          • 加載進(jìn)度條時(shí)間:瀏覽器 onload 事件觸發(fā)時(shí)間,觸發(fā)后導(dǎo)航欄進(jìn)度條顯示完成。

          Chrome 模擬器 4G 無(wú)緩存對(duì)比(左優(yōu)化前、右優(yōu)化后):





          首屏最大內(nèi)容繪制時(shí)間 進(jìn)度條加載(onload)時(shí)間
          優(yōu)化前 1067 ms 6.18s
          優(yōu)化后 31 ms 優(yōu)化 80%(120 ms) 1.19s 優(yōu)化 81%


          Lighthouse 跑分對(duì)比:

          優(yōu)化前:


          優(yōu)化后:



          性能得分
          優(yōu)化前 平均 40 ~ 50
          優(yōu)化后 平均 75 ~ 85 提升 47%


          srobot 性能檢測(cè)一周數(shù)據(jù)

          srobot 是團(tuán)隊(duì)內(nèi)的性能檢測(cè)工具,使用 TRobot 指令一鍵創(chuàng)建頁(yè)面健康檢測(cè),定時(shí)自動(dòng)化檢測(cè)頁(yè)面性能及異常。

          優(yōu)化前:

          優(yōu)化后:


          進(jìn)度條平均加載(onload)時(shí)間(4G)
          優(yōu)化前 4632ms
          優(yōu)化后 2581ms 提升45%


          五、優(yōu)化總結(jié)和未來(lái)規(guī)劃

          1. 以上優(yōu)化手段主要是圍繞首次加載頁(yè)面的耗時(shí)和渲染優(yōu)化,但二次加載還有很大的優(yōu)化空間 如 PWA 的使用、非直出頁(yè)面骨架屏處理、CSR 轉(zhuǎn) SSR等

          2. 對(duì)比競(jìng)品發(fā)現(xiàn)我們 CDN 的下載耗時(shí)較長(zhǎng),近期準(zhǔn)備啟動(dòng) CDN 上云,期待上云后 CDN 的效果提升。

          3. 項(xiàng)目迭代一直在進(jìn)行,需要思考在工程上如何持續(xù)保障頁(yè)面性能

          4. 上文是圍繞課程詳情頁(yè)進(jìn)行的分析和優(yōu)化處理,雖然對(duì)項(xiàng)目整體做了優(yōu)化處理,但性能優(yōu)化沒(méi)有銀彈,不同頁(yè)面的優(yōu)化要根據(jù)頁(yè)面具體需求進(jìn)行,需要開(kāi)發(fā)同學(xué)主動(dòng)關(guān)注。

          感謝耐心閱讀,歡迎大家交流,指正文中錯(cuò)誤和疏漏,一起學(xué)習(xí)!

          Node 社群


          我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。


             “分享、點(diǎn)贊在看” 支持一波?? 

          瀏覽 57
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美一级免费看 | 久久女人高朝视频免费看 | 国产又粗又猛 | 久久99e | 青青草激情在线视频 |