<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>

          基于RUM的前端優(yōu)化理論與實踐-性能篇

          共 7392字,需瀏覽 15分鐘

           ·

          2021-09-12 23:07


          前言


          對于前端來說,最重要的是體驗,而在前端體驗中,最為核心的就是性能。 


          相信大多數(shù)用戶接入前端性能監(jiān)控(RUM)都是為了通過RUM質(zhì)量評價體系來驗證前端性能和質(zhì)量如何,而直接影響性能和質(zhì)量的則是一系列的指標(biāo),因此了解頁面性能指標(biāo)顯得格外重要!

          前端性能監(jiān)控RUM是騰訊云的大前端領(lǐng)域頁面質(zhì)量和性能監(jiān)控平臺,聚焦提升用戶體驗。了解詳情

          通俗點說,某用戶想了解頁面訪問速度快,是否快,究竟有多快?怎么衡量?需要一個中立的裁判來裁決,而RUM的角色正是這個裁判。

          本文會結(jié)合前端監(jiān)控SDK源碼-Aegis和Google最新的頁面性能規(guī)范為大家講解下列兩大主題:

          1. 前端頁面性能關(guān)鍵指標(biāo)的規(guī)范和計算規(guī)則。


          2. 如何看懂RUM可視化圖表?并通過圖表數(shù)據(jù)進(jìn)行項目優(yōu)化?



          頁面性能指標(biāo)有哪些?


          在前端監(jiān)控中指標(biāo)眾多繁雜,例如:白屏?xí)r間、首屏?xí)r間、FCP、FMP、LCP、FID、TTFB等等,一般人難以把握。我們從中抽取一些最常見,最實用的規(guī)范跟大家一一解釋。

          • 網(wǎng)絡(luò)連接瀑布圖(TL;DR)


          要解釋這些指標(biāo),還是要先祭出網(wǎng)絡(luò)連接瀑布圖,想必只要對頁面性能稍有了解的用戶都見過這張圖。




          與這張圖一一對應(yīng)的,是瀏覽器里面的`performance.timing`屬性,我們將其同時打印出來,做一個數(shù)據(jù)的對比說明。



          • navigationStart:表示從上一個文檔卸載結(jié)束時的unix時間戳,如果沒有上一個文檔,這個值將和fetchStart相等。

          • unloadEventStart:表示前一個網(wǎng)頁(與當(dāng)前頁面同域)unload的時間戳,如果無前一個網(wǎng)頁unload或者前一個網(wǎng)頁與當(dāng)前頁面不同域,則值為0。


          • unloadEventEnd:返回前一個頁面unload時間綁定的回調(diào)函數(shù)執(zhí)行完畢的時間戳。


          • redirectStart:第一個HTTP重定向發(fā)生時的時間。有跳轉(zhuǎn)且是同域名內(nèi)的重定向才算,否則值為0。


          • redirectEnd:最后一個HTTP重定向完成時的時間。有跳轉(zhuǎn)且是同域名內(nèi)部的重定向才算,否則值為0。


          • fetchStart:瀏覽器準(zhǔn)備好使用HTTP請求抓取文檔的時間,這發(fā)生在檢查本地緩存之前。

          • domainLookupStart/domainLookupEnd:DNS域名查詢開始/結(jié)束的時間,如果使用了本地緩存(即無DNS查詢)或持久連接,則與fetchStart值相等。


          • connectStart:HTTP(TCP)開始/重新 建立連接的時間,如果是持久連接,則與fetchStart值相等。


          • connectEnd:HTTP(TCP) 完成建立連接的時間(完成握手),如果是持久連接,則與fetchStart值相等。


          • secureConnectionStart:HTTPS連接開始的時間,如果不是安全連接,則值為0。


          • requestStart:HTTP請求讀取真實文檔開始的時間(完成建立連接),包括從本地讀取緩存。


          • responseStart:HTTP開始接收響應(yīng)的時間(獲取到第一個字節(jié)),包括從本地讀取緩存。


          • responseEnd:HTTP響應(yīng)全部接收完成的時間(獲取到最后一個字節(jié)),包括從本地讀取緩存。


          • domLoading:開始解析渲染DOM樹的時間,此時 Document.readyState變?yōu)閘oading,并將拋出readystatechange相關(guān)事件。


          • domInteractive:完成解析DOM樹的時間,Document.readyState變?yōu)閕nteractive,并將拋出readystatechange相關(guān)事件,注意只是DOM樹解析完成,這時候并沒有開始加載網(wǎng)頁內(nèi)的資源。


          • domContentLoadedEventStart:DOM解析完成后,網(wǎng)頁內(nèi)資源加載開始的時間,在DOMContentLoaded事件拋出前發(fā)生。


          • domContentLoadedEventEnd:DOM解析完成后,網(wǎng)頁內(nèi)資源加載完成的時間(如JS腳本加載執(zhí)行完畢)。


          • domComplete::DOM樹解析完成,且資源也準(zhǔn)備就緒的時間,Document.readyState變?yōu)閏omplete,并將拋出readystatechange相關(guān)事件。


          • loadEventStart:load事件發(fā)送給文檔,也即load回調(diào)函數(shù)開始執(zhí)行的時間。


          • loadEventEnd:load事件的回調(diào)函數(shù)執(zhí)行完畢的時間。


          根據(jù)上述的定義,我們總結(jié)出來常見的頁面指標(biāo)的計算公式:


          // 計算加載時間getPerformanceTiming() {const t = performance.timing;const times = {};// 頁面加載完成的時間,用戶等待頁面可用的時間  times.loadPage = t.loadEventEnd - t.navigationStart;// 解析 DOM 樹結(jié)構(gòu)的時間  times.domReady = t.domComplete - t.responseEnd;// 重定向的時間  times.redirect = t.redirectEnd - t.redirectStart;// DNS 查詢時間  times.lookupDomain = t.domainLookupEnd - t.domainLookupStart;// 讀取頁面第一個字節(jié)的時間  times.ttfb = t.responseStart - t.navigationStart;// 資源請求加載完成的時間  times.request = t.responseEnd - t.requestStart;// 執(zhí)行 onload 回調(diào)函數(shù)的時間  times.loadEvent = t.loadEventEnd - t.loadEventStart;// DNS 緩存時間  times.appcache = t.domainLookupStart - t.fetchStart;// 卸載頁面的時間  times.unloadEvent = t.unloadEventEnd - t.unloadEventStart;// TCP 建立連接完成握手的時間  times.connect = t.connectEnd - t.connectStart;return times;}

          ?


          RUM使用了哪些性能指標(biāo)?


          下列我通過各前主流圖表來深入了解RUM的性能指標(biāo)。

          • 頁面加載瀑布圖


          瀑布圖是表示網(wǎng)站資源如何下載、由引擎解析的圖表,其包含首耗時、請求響應(yīng)等8個性能指標(biāo),它讓我們可以查看資源之間的順序和依賴關(guān)系。有助于確定加載過程中發(fā)生重要事件的位置,還可以讓用戶輕松看到他們的網(wǎng)站性能的好壞,從而準(zhǔn)確顯示哪些速度正在減慢網(wǎng)站性能。



          Aegis SDK源碼中對其的計算規(guī)則如下:


          const t: PerformanceTiming = performance.timing;if (!t) return;// 這里不知道為什么有時候 t.loadEventStart - t.domInteractive 返回一個很大的負(fù)數(shù),暫時先簡單處理let resourceDownload = t.loadEventStart - t.domInteractive;if (resourceDownload < 0) resourceDownload = 1070;result = {dnsLookup: t.domainLookupEnd - t.domainLookupStart,tcp: t.connectEnd - t.connectStart,ssl: t.secureConnectionStart === 0 ? 0 : t.requestStart - t.secureConnectionStart,ttfb: t.responseStart - t.requestStart,contentDownload: t.responseEnd - t.responseStart,domParse: t.domInteractive - t.domLoading,resourceDownload};


          備注:`resourceDownload`有時會出現(xiàn)一個極大的負(fù)數(shù),所以做了簡單兼容,取了幾個項目的平均值。其他的頁面性能指標(biāo)計算規(guī)則大家可以通過代碼比較直觀的看出來。

          RUM中有一個首屏?xí)r間,那么Aegis SDK是如何計算這個指標(biāo)的呢?

          1. 默認(rèn)通過MutationObserver這個API來監(jiān)控瀏覽器document對象的DOM變化,只計算在首屏內(nèi)的DOM元素,把DOM變化時間作為x軸,單位時間內(nèi)DOM變化的數(shù)量作為y軸,繪制曲線后,我們找到DOM變化最高點,認(rèn)為是首屏完成。

          2. 如果開發(fā)者覺得該算法不準(zhǔn)確,希望自己標(biāo)記DOM元素,可以添加屬性<div AEGIS-FIRST-SCREEN-TIMING></div>,把某個元素識別為首屏關(guān)鍵元素,SDK認(rèn)為只要用戶首屏出現(xiàn)此元素就是首屏完成。也可以添加屬性<div AEGIS-IGNORE-FIRST-SCREEN-TIMING></div>,把該DOM列入黑名單。



          除了上述的數(shù)據(jù)外,RUM還根據(jù)上報的數(shù)據(jù)計算了以上幾個頁面性能相關(guān)的指標(biāo)。計算公式如下:

          1. 首字節(jié)(TTFB)=DNS+SSL+TCP+TTFB

          2. DOMReady=DNS+SSL+TCP+TTFB+ContentDownload+DomParse

          3. 頁面完全加載=DNS+SSL+TCP+TTFB+ContentDownload+ DomParse+ResourceDownload


          • 良好網(wǎng)站的基本指標(biāo)-Web Vitals


          上述計算首屏的算法是Aegis SDK自主提供的算法,用戶場景千變?nèi)f化,無法覆蓋所有場景,而且這個算法也無法得到所有開發(fā)者的認(rèn)同。這個時候就需要祭出Web Vitals了


          什么是Web Vitals?


          Google給的定義是一個良好網(wǎng)站的基本指標(biāo) (Essential metrics for a healthy site)。

          為什么還要再定義一個新的指標(biāo)集呢?

          因為過去要衡量一個好的網(wǎng)站,需要使用的指標(biāo)太多,推出Web Vitals是簡化這個學(xué)習(xí)的曲線,站主只要關(guān)注Web Vitals指標(biāo)表現(xiàn)即可。



          目前Google的Web Vitals源碼中提供了5個指標(biāo),分別為:

          1. CLS(Cumulative Layout Shift-累積布局移位):CLS會衡量在網(wǎng)頁的整個生命周期內(nèi)發(fā)生的所有意外布局偏移的得分總和。得分是零到任意正數(shù),其中0表示無偏移,且數(shù)字越大,網(wǎng)頁的布局偏移越大。

          2. FCP(First Contentful Paint-首次內(nèi)容繪制):FCP度量從頁面開始加載到頁面內(nèi)容的任何部分呈現(xiàn)在屏幕上的時間,頁面內(nèi)容包括文本、圖像(包括背景圖像)、<svg>元素或非白色的<canvas>元素。

          3. FID(First Input Delay-首次輸入延遲):從用戶首次與您的網(wǎng)頁互動(點擊鏈接、點按按鈕,等等)到瀏覽器響應(yīng)此次互動之間的用時。這種衡量方案的對象是被用戶首次點擊的任何互動式元素。

          4. LCP(Largest Contentful Paint-最大內(nèi)容繪制):LCP度量從用戶請求網(wǎng)址到在視口中渲染最大可見內(nèi)容元素所需的時間。最大的元素通常是圖片或視頻,也可能是大型塊級文本元素。

          5. TTFB (Time To First Byte-從服務(wù)器接收到第一個字節(jié)耗時) :TTFB 是發(fā)出頁面請求到接收到應(yīng)答數(shù)據(jù)第一個字節(jié)的時間總和,它包含了DNS解析時間、TCP連接時間、發(fā)送HTTP請求時間和獲得響應(yīng)消息第一個字節(jié)的時間。

          目前 RUM采有了其中最重要的三個屬性:LCP,F(xiàn)ID和CLS。

          這里可以看出與之前 “首屏?xí)r間” 比較模糊的定義不同,Google對Web Vitals給出了非常明確的指標(biāo)定義,并且官方提供了算法支持,那么我們是不是可以直接用LCP取代我們自己寫的 “首屏算法” 呢?目前顯然還是不可行的,由于LCP底層使用的是PerformanceObserver,還存在兼容性問題,因此短期內(nèi)還無法完全替代。



          不過,在可預(yù)見的未來,Web Vitals會成為業(yè)界的主流衡量標(biāo)準(zhǔn),到那個時候,我們也可以卸下歷史包袱,全面擁抱開源算法了。


          如何分析性能數(shù)據(jù)&指導(dǎo)開發(fā)優(yōu)化?



          擁有了RUM這個好用的工具,下面就可以用數(shù)據(jù)指導(dǎo)開發(fā)和決策了。


          我們的項目接入到RUM后,怎么樣根據(jù)RUM展示的數(shù)據(jù)來優(yōu)化項目呢?

          • 優(yōu)化舉例


          下列拿某團(tuán)隊邀請我們對其項目做的一次針對性優(yōu)化舉例。


          首先開發(fā)者的核心訴求是頁面響應(yīng)快,性能好。而上圖這個數(shù)據(jù)無論如何都稱不上快,可以看到首屏?xí)r間達(dá)到了4.8s,LCP的時間超過了4s,僅僅達(dá)到了“POOR”的級別,CLS的數(shù)據(jù)也不容樂觀。

          我們首先僅從表面數(shù)據(jù)進(jìn)行分析,對比了該項目下全部頁面的數(shù)據(jù),通過“Top訪問頁面” tab對頁面進(jìn)行分析,先按照“首屏?xí)r間”倒排序。


          這里發(fā)現(xiàn)了第一個問題,開發(fā)者把多個項目的頁面都使用了同一個上報ID進(jìn)行上報,導(dǎo)致一些比較差的頁面對整體數(shù)據(jù)產(chǎn)生了影響,因此我們建議用戶盡可能根據(jù)代碼組織業(yè)務(wù)組織的方式區(qū)分不同的上報ID,方便定點發(fā)現(xiàn)問題。

          排除了頁面的干擾,我們再分析一下網(wǎng)絡(luò)和區(qū)域干擾。



          從上圖可以看出來,網(wǎng)絡(luò)狀況和地區(qū)差異對頁面首屏數(shù)據(jù)影響都不是很大。

          再回到前面的瀑布圖,從圖中可以看到該項目主要的瓶頸其實在“資源加載”的耗時。通過對用戶頁面的資源加載情況進(jìn)行分析,立刻找到了原因。


          用戶使用的是React框架,在沒有服務(wù)端渲染的情況下,頁面是會在加載主JS后才渲染的,而用戶大部分JS文件都打包成一個bundle,導(dǎo)致產(chǎn)生了一個超大的JS文件,這個JS文件就成為了用戶頁面渲染的瓶頸。除此之外還發(fā)現(xiàn)了該JS文件沒有支持HTTP2協(xié)議。

          • 資源加載優(yōu)化


          根據(jù)上述數(shù)據(jù)顯示,我們建議用戶做以下優(yōu)化:

          1. 拆包,通過把公共外部依賴打包成為vendor,并且對組件做異步加載


          2. 去掉一些非必需的包,比如用戶引入了全量的lodash,讓其改成lodash-es,方便webpacktreeshaking;去掉僅為了把某個時間做格式化而引入的moment;去掉jquery,而當(dāng)初引入jquery僅僅為了查詢某個元素而,真是得不償失。


          3. 建議使用webpack-bundle-analyzer對打包后的代碼進(jìn)行分析,查看哪些包不需要引用,或者可以單獨打包。


          4. 網(wǎng)絡(luò)協(xié)議方面全面引入HTTP2,合并了一些小的靜態(tài)資源,把一些小的svg改成了base64。


          通過簡單的分析,找到頁面性能洼地,用戶根據(jù)建議簡單優(yōu)化,效果十分顯著,全量發(fā)布后不久數(shù)據(jù)就得到大幅提升,首屏?xí)r間從4.8s優(yōu)化到3.2s,最重要的是 “資源加載” 耗時直接減半。


          然后發(fā)現(xiàn)了另外一個問題,用戶的 “資源加載” 時間已經(jīng)大幅度降低了,但是為什么 “首屏耗時” 沒有相應(yīng)的同比降低呢?

          我們通過對用戶頁面分析發(fā)現(xiàn),該頁面在加載完成后,會執(zhí)行非常多的JS代碼邏輯,包括一些數(shù)據(jù)上報,用戶行為收集,還有加載側(cè)邊欄,彈出廣告等。這里帶來了2個問題。

          1. 頁面主進(jìn)程阻塞嚴(yán)重,Aegis SDK的一些邏輯在執(zhí)行的時候受到了影響,導(dǎo)致實際執(zhí)行時間要晚于設(shè)定的時間,所以上報的“首屏耗時”其實要比實際晚的。


          2. 用戶的頁面會在首屏完成后,繼續(xù)加載很多DOM元素,也就是有很多DOM元素的變化,導(dǎo)致了Aegis SDK計算出來的首屏?xí)r間也要晚于真實的“首屏?xí)r間”。


          于是我們建議用戶把一些非必要操作都放在定時器中執(zhí)行,以提升頁面性能,提升用戶體驗。用戶根據(jù)我們的建議通過定時器和異步改造,又大幅度提升了頁面的“首屏?xí)r間”。



          這個時候的“首屏耗時”已經(jīng)是優(yōu)化之初的1/2了,對于大多數(shù)用戶來說,50%的性能提升其實已經(jīng)可以去交差了,但是我們看到用戶另外幾個指標(biāo)依然不是很完美。其中CLS的得分一直是“POOR”的狀態(tài)。

          • CLS指標(biāo)優(yōu)化


          CLS指的是頁面布局偏移量,再次簡單分析,我們發(fā)現(xiàn)用戶有一個長列表是頁面主要渲染內(nèi)容,該列表存在的問題是:因為數(shù)據(jù)不多,一般在4-10條數(shù)據(jù),所以開發(fā)者沒有對列表做分頁。

          沒有分頁帶來的問題是,列表無法在渲染之初就確定長度,導(dǎo)致獲取數(shù)據(jù)后渲染列表的時候頁面發(fā)生較大的偏移,同時也帶來了超多的DOM變化。

          這個是導(dǎo)致CLS大的核心原因,當(dāng)然也帶來了“首屏耗時”的同步增加,除此之外,前面提到的一些異步數(shù)據(jù),如廣告掛件等也帶來了這個問題。
          給用戶的建議如下:

          1. 一開始就確定列表高度(加入分頁),通過骨架屏優(yōu)化加載效果,同時減少DOM變化。


          2. 廣告掛件使用絕對布局,使其脫離文檔流,減少DOM變化。


          3. 一些其他元素,如圖片等,確定長度和寬度屬性,這些值允許瀏覽器在將圖像渲染到位之前保留視覺空間。


          4. 一些元素的變化,通過CSS實現(xiàn),而不是使用JS改變元素屬性實現(xiàn)。


          再次優(yōu)化后用戶頁面首屏和CLS數(shù)據(jù)變化驚人,達(dá)到了業(yè)界主流水平。最后我們看一下整體數(shù)據(jù)效果。



          就目前的數(shù)據(jù)來看,用戶頁面性能仍然有可提升空間,更深層次的優(yōu)化需要借助Chrome Performance工具進(jìn)行了解,我們會以這個主題另開一篇文章進(jìn)行講解和分析,敬請期待。


          總結(jié)


          以上僅僅是我們使用RUM做優(yōu)化的鳳毛麟角,其中涉及到的知識都是前端開發(fā)耳熟能詳?shù)摹N覀冎荚谕ㄟ^好用的工具,指導(dǎo)開發(fā)同學(xué)做決策,從而達(dá)到優(yōu)化的效果。引用Lord Kelvin的一句名言,如果你無法衡量它,你就無法提升它



           作者簡介


          李振

          騰訊云高級工程師

          李振,騰訊云高級工程師,騰訊內(nèi)部最受歡迎的前端開源項目TAM負(fù)責(zé)人,騰訊云前端性能監(jiān)控RUM負(fù)責(zé)人,有豐富的前端開發(fā)和產(chǎn)品研發(fā)經(jīng)驗。





          點擊閱讀原文」,立即體驗RUM~

          瀏覽 67
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  天天摸日日摸狠狠添 | 黄色一级电影网站 | 伊人午夜av | 精品国产AⅤ一区二区三区东京热 | 无码免费性爱视频 |