<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    做性能優(yōu)化時(shí),我們關(guān)注哪些指標(biāo)?

    共 7743字,需瀏覽 16分鐘

     ·

    2021-10-22 04:10

    大廠技術(shù)??爆肝日更??精選好文

    前一段時(shí)間,我們對(duì) webview 做了一期性能優(yōu)化,在優(yōu)化過(guò)程中,我們追求的是頁(yè)面要足夠「快」「穩(wěn)」。那怎么定量地衡量這個(gè)「快」「穩(wěn)」呢?性能指標(biāo)幫助我們從數(shù)據(jù)化角度了解頁(yè)面性能現(xiàn)狀,性能瓶頸以及優(yōu)化完成后,衡量?jī)?yōu)化效果。

    性能指標(biāo)在日常開(kāi)發(fā)中,大家或多或少的都有接觸。比如?? 是一個(gè)頁(yè)面在 Lighthouse 下跑出來(lái)的性能數(shù)據(jù)。

    bae5edf37ccd54a33faa49eabec5a31d.webp

    這篇文章將回答下面幾個(gè)問(wèn)題:

    • 哪些性能指標(biāo)是需要觀測(cè)的?它們是什么含義?
    • 這么多指標(biāo),我們?cè)谑裁磮?chǎng)景下應(yīng)該關(guān)注哪些?
    • 指標(biāo)是怎么采集的?
    常用的性能指標(biāo)
    • First Paint
    • First Contentful Paint
    • Largest Contentful Paint
    • First Meaningful Paint
    • First Input Delay
    • Cumulative Layout Shift
    • Time to Interactive
    • DOMContentLoaded
    • Load

    First Paint(FP) 首次繪制

    首次渲染的時(shí)間點(diǎn),可以視為白屏?xí)r間,比如完成背景色渲染的時(shí)間點(diǎn)。通常作為時(shí)間點(diǎn)最早的一個(gè)性能指標(biāo)。

    First Contentful Paint(FCP) 首次內(nèi)容繪制

    首次有內(nèi)容渲染的時(shí)間點(diǎn),指標(biāo)測(cè)量頁(yè)面從開(kāi)始加載到頁(yè)面內(nèi)容的任何部分在屏幕上完成渲染的時(shí)間。對(duì)于該指標(biāo),"內(nèi)容"指的是文本、圖像、元素或非白色的元素??梢宰鳛槭灼?xí)r間。

    FP vs FCP

    FP:從開(kāi)始加載到第一次渲染

    FCP:從開(kāi)始加載到第一次內(nèi)容渲染。

    FCP 是 FP 的增強(qiáng)版,對(duì)用戶來(lái)說(shuō)更關(guān)鍵。因?yàn)?FCP 帶著圖像和文字這些內(nèi)容信息,是用戶更關(guān)心的。

    FP 和 FCP 可能是重合的。

    1512d00e3edbfdb1a330e2e0505db781.webp

    Largest Contentful Paint (LCP) 最大內(nèi)容繪制

    頁(yè)面的最大內(nèi)容(通常是比較核心的內(nèi)容)加載完成的時(shí)間,這個(gè)最大內(nèi)容可以是圖片/文本塊。它是一個(gè) SEO 相關(guān)的指標(biāo)。

    LCP vs FCP

    FCP:頁(yè)面加載過(guò)程中,比較早期的一個(gè)指標(biāo),如果一個(gè)頁(yè)面有 loading 態(tài),這個(gè)指標(biāo)表現(xiàn)可能很好,但是實(shí)際內(nèi)容什么時(shí)候呈現(xiàn)給用戶,這個(gè)指標(biāo)沒(méi)辦法衡量。

    LCP:關(guān)注頁(yè)面核心內(nèi)容呈現(xiàn)時(shí)間,這個(gè)內(nèi)容是用戶更感興趣的,更加用戶相關(guān)。

    705261616a40757166f4ad90f7fc32d8.webp

    First Meaningful Paint(FMP) 首次有效繪制

    首次繪制有意義內(nèi)容的時(shí)間。業(yè)界比較認(rèn)可的方式是在加載和渲染過(guò)程中最大布局變動(dòng)之后的那個(gè)繪制時(shí)間即為當(dāng)前頁(yè)面的 FMP。因?yàn)樗?jì)算相對(duì)復(fù)雜,且存在準(zhǔn)確性等問(wèn)題,Lighthouse 6.0 中被廢棄。

    LCP vs FMP

    FMP: 早期比較推薦的性能指標(biāo),但是計(jì)算更復(fù)雜,而且準(zhǔn)確性不是很好

    LCP: 更新的數(shù)據(jù)指標(biāo),有 API 直接支持,統(tǒng)計(jì)簡(jiǎn)單,且準(zhǔn)確,但也存在最大內(nèi)容是否為最核心內(nèi)容這樣的問(wèn)題。

    First Input Delay(FID) 首次輸入延遲

    這個(gè)指標(biāo)的觸發(fā)是在用戶第一次與頁(yè)面交互的的時(shí)候,記錄的是是用戶第一次與頁(yè)面交互到瀏覽器真正能夠開(kāi)始處理事件處理程序以響應(yīng)該交互的時(shí)間,即交互延遲時(shí)間。比如發(fā)生在用戶第一次在頁(yè)面進(jìn)行 click, keydown 等交互。

    為什么會(huì)有這樣的延遲呢?一般來(lái)說(shuō),發(fā)生輸入延遲是因?yàn)闉g覽器的主線程正忙著執(zhí)行其他工作(比如解析和執(zhí)行大型 JS 文件),還不能響應(yīng)用戶。

    Cumulative Layout Shift(CLS) 累積布局偏移

    在一個(gè)頁(yè)面的生命周期中,會(huì)不斷的發(fā)生布局變化(layout shift),對(duì)每一次布局變化做一個(gè)累積的記分,其中得分最大布局變化即為 CLS。是衡量頁(yè)面穩(wěn)定性的重要指標(biāo)(visual stability)

    糟糕的 CLS 對(duì)用戶體驗(yàn)的影響??

    f6dd542151d8a82a88cbe0f91ea59320.webp

    Core Web Vitals

    2020 年 5 月,Google 提出的衡量網(wǎng)站用戶體驗(yàn)的核心數(shù)據(jù)指標(biāo),涵蓋了頁(yè)面的加載速度、可交互性和穩(wěn)定性。是近期生效的會(huì)影響 SEO 的重要指標(biāo),包含一下三項(xiàng):

    • LCP
    • FID
    • CLS

    Time to Interactive(TTI) 可交互時(shí)間

    說(shuō)到 TTI 首先要介紹下 Long Task

    Long Task:如果瀏覽器主線程執(zhí)行的一個(gè) task 耗時(shí)大于 50ms,那么這個(gè) task 稱為 long task。用戶的交互操作也是在主線程執(zhí)行的,所以當(dāng)發(fā)生 Long Task 時(shí),用戶的交互操作很可能無(wú)法及時(shí)執(zhí)行,這時(shí)用戶就會(huì)體驗(yàn)到卡頓(當(dāng)頁(yè)面響應(yīng)時(shí)間超過(guò) 100ms 時(shí),用戶可以體驗(yàn)到卡頓),進(jìn)而影響用戶體驗(yàn)。

    從頁(yè)面加載開(kāi)始到頁(yè)面處于完全可交互狀態(tài)所花費(fèi)的時(shí)間。通常是發(fā)生在頁(yè)面依賴的資源已經(jīng)加載完成,此時(shí)瀏覽器可以快速響應(yīng)用戶交互的時(shí)間。

    DOMContentLoaded(DCL)

    DOM 加載完成即觸發(fā),不用等頁(yè)面資源加載。

    Load(L)

    頁(yè)面及其依賴的資源全部加載完成的時(shí)間,包括所有的資源文件,如樣式表和圖片等。

    常見(jiàn)的性能名詞

    以用戶為中心的性能指標(biāo) (user-centric metric)

    傳統(tǒng)性能指標(biāo):

    很長(zhǎng)時(shí)間以來(lái),描述性能是通過(guò) Load/DOMContentLoaded 事件進(jìn)行測(cè)量的,一個(gè)網(wǎng)站加載完成的時(shí)間是多少秒。雖然 Load/DOMContentLoaded 是頁(yè)面生命周期中比較明確的時(shí)刻,但是它真的能很好的反應(yīng)實(shí)際用戶訪問(wèn)頁(yè)面的真實(shí)感受嗎?

    比如,服務(wù)器如果響應(yīng)一個(gè)很小的體積的頁(yè)面,Load/DOMContentLoaded 會(huì)很快觸發(fā),然后異步獲取內(nèi)容,之后在頁(yè)面上顯示。這樣的頁(yè)面 Load/DOMContentLoaded 的時(shí)間很短,那從用戶體驗(yàn)角度講它的性能表現(xiàn)就是好的嗎?

    要回答上面問(wèn)題,也就引出了?? 這個(gè)概念。

    以用戶為中心的性能指標(biāo) (user-centric metric):

    以用戶為中心的性能指標(biāo)更關(guān)注從用戶角度看,頁(yè)面的性能是怎樣的?頁(yè)面呈現(xiàn)的內(nèi)容是不是滿足用戶需要,用戶交互起來(lái)是否流暢等。上面介紹的 FCP、LCP、FMP、FID、CLS、TTI 均是以用戶為中心的性能指標(biāo)

    是否正在發(fā)生?導(dǎo)航是否成功啟動(dòng)?服務(wù)器有響應(yīng)嗎?
    是否有用?是否渲染了足夠的內(nèi)容讓用戶可以深入其中?
    是否可用?頁(yè)面是否繁忙,用戶是否可以與頁(yè)面進(jìn)行交互?
    是否令人愉快?交互是否流暢自然,沒(méi)有延遲和卡頓?

    根據(jù)采集方式不同,性能指標(biāo)的幾種形式

    根據(jù)測(cè)量方式的不同,性能數(shù)據(jù)可以分為:Lab Data 和 Field Data

    Lab Data / SYN

    SYN 即 synthetic monitoring,收集形式也有叫 in the lab

    Lab Data 是在可控的條件下,特定的機(jī)型,特定的網(wǎng)絡(luò)環(huán)境,收集的性能數(shù)據(jù)。一個(gè)使用場(chǎng)景是,新頁(yè)面開(kāi)發(fā)的時(shí)候,頁(yè)面發(fā)布到生產(chǎn)環(huán)境中之前,是沒(méi)辦法基于真實(shí)用戶做性能指標(biāo)測(cè)量的,此時(shí),想了解也沒(méi)性能情況,可以通過(guò) Lab 方式收集和檢查。

    Field Data / RUM

    RUM 即 Real User Monitoring,收集形式也有叫 in the Filed

    Lab 的方式測(cè)量雖然能反應(yīng)性能情況,但是真實(shí)用戶因機(jī)型和網(wǎng)絡(luò)情況各異,頁(yè)面加載對(duì)于不同用戶具有很大的不確定性,Lab 數(shù)據(jù)并不一定是真實(shí)用戶的實(shí)際情況。而 filed 數(shù)據(jù)很好的解決了這個(gè)問(wèn)題,有一定的代碼侵入性,記錄真實(shí)用戶的性能數(shù)據(jù),通過(guò) RUM 數(shù)據(jù)可以發(fā)現(xiàn)一些 Lab 數(shù)據(jù)下很難暴露出來(lái)的性能異常。

    RAIL Model

    我們先來(lái)看下 RAIL 這幾個(gè)字母分別對(duì)應(yīng)什么?

    R: response

    A: animation

    I: idle

    L: load

    RAIL 是 Google 提出的以用戶為中心的一套性能模型,從各個(gè)維度反應(yīng)一個(gè)網(wǎng)站的性能情況,同時(shí)提供一組性能目標(biāo)供參考??

    • Response: 50ms 內(nèi)對(duì)事件做出響應(yīng)
    • Animation: 動(dòng)畫(huà) 10 ms 內(nèi)生成內(nèi)一幀(每幀耗時(shí) 16ms,用戶會(huì)感到動(dòng)畫(huà)流暢,為什么這里是 10ms?)
    • Idle: 最大化的利用上空閑時(shí)間
    • Load: 在 5s 內(nèi)完成內(nèi)容傳輸并達(dá)到用戶可交互
    性能指標(biāo)是怎么采集的

    性能指標(biāo)相關(guān)的 API 及采集方式

    Performance Observer[1]

    Performance Observer API 下包含一組性能監(jiān)測(cè)相關(guān)的 API

    • Paint Timing API
    • Largest Contentful Paint API
    • Event Timing API
    • Navigation Timing API
    • Layout Instability API
    • Long Tasks API
    • Resource Timing API

    下面按照不同指標(biāo)的收集用到的 API 依次介紹它們是怎么用的。

    Paint Timing API[2]

    用于收集 FP / FCP

    new?PerformanceObserver((list)?=>?{

    ??for?(const?entry?of?list.getEntries())?{

    ????console.log('FCP:?',?entry.startTime);

    ??}

    }).observe({

    ??type:?'first-contentful-paint',

    ??buffered:?true,

    });



    new?PerformanceObserver((list)?=>?{

    ??for?(const?entry?of?list.getEntries())?{

    ????console.log('FP:?',?entry.startTime);

    ??}

    }).observe({

    ??type:?'first-paint',

    ??buffered:?true,

    });

    Largest Contentful Paint API[3]

    用于收集 LCP

    largest-contentful-paint 事件會(huì)在頁(yè)面加載過(guò)程中根據(jù)此時(shí)已渲染最大元素的變化,不斷的被觸發(fā),實(shí)際上報(bào)中會(huì)一直監(jiān)聽(tīng)這些變化,直到用戶與頁(yè)面發(fā)生交互行為(比如 click、keydown)或者頁(yè)面被隱藏或者頁(yè)面被 unload 等,取監(jiān)聽(tīng)到的最后值做上報(bào)。

    new?PerformanceObserver(entryList?=>?{

    ??for?(const?entry?of?entryList.getEntries())?{

    ????console.log('LCP:?',?entry.startTime);

    ??}

    }).observe({

    ????type:?'largest-contentful-paint',

    ????buffered:?true

    });

    3cab1ede84c4b6fe9db13983f6f972db.webp0488772b0a66840b977a3dd7db36c002.webp95f6b8313b83744c513c3601d33feb9d.webp380c77048b9e254b719e4446fb86143b.webp

    dce8ad55a0595d715896abd8865d660f.webp

    完整版代碼參考?? https://github.com/GoogleChrome/web-vitals/blob/main/src/getLCP.ts

    這個(gè)指標(biāo)是 Core Web Vitals,但是兼容性不好,iOS 下都是不支持的??

    8c14e5fa01d9ce8abe78d3b32c303661.webp

    Event Timing API[4]

    用于收集 FID

    監(jiān)聽(tīng)用戶的第一次輸入(first-input)事件,F(xiàn)ID = 開(kāi)始處理 input 的時(shí)間 - input 操作的起始時(shí)間

    new?PerformanceObserver(list?=>?{

    ??for?(const?entry?of?list.getEntries())?{

    ????//?開(kāi)始處理?input?的時(shí)間?-?input?操作的起始時(shí)間

    ????const?FID?=?entry.processingStart?-?entry.startTime;?

    ????console.log('FID:',?FID);

    ??}

    }).observe({

    ??type:?'first-input',

    ??buffered:?true,

    });

    Navigation Timing 1.0[5] 或 Navigation Timing 2.0[6]

    用于收集 Load / DOMContentLoaded

    ac6c9e99a6ef9b5e4b0bfa64a05749b0.webp
    new?PerformanceObserver(list?=>?{

    ??for?(const?entry?of?list.getEntries())?{

    ????const?Load?=?entry.loadEventStart?-?entry.fetchStart;

    ????console.log('Load:',?Load);

    ??}

    }).observe({

    ??type:?'navigation',

    ??buffered:?true,

    });



    new?PerformanceObserver(list?=>?{

    ??for?(const?entry?of?list.getEntries())?{

    ????const?DOMContentLoaded?=?entry.domContentLoadedEventStart?-?entry.fetchStart;

    ????console.log('DOMContentLoaded:',?DOMContentLoaded);

    ??}

    }).observe({

    ??type:?'navigation',

    ??buffered:?true,

    });

    Layout Instability API[7]

    收集 CLS: 將加載過(guò)程分塊(session),監(jiān)聽(tīng) layout-shift 變化獲得每次布局變動(dòng)的 value 值,統(tǒng)計(jì)每個(gè) session 的布局變動(dòng)分?jǐn)?shù),最大的布局變動(dòng)分?jǐn)?shù)時(shí)段,即為 CLS。

    let?sessionEntries?=?[];

    let?sessionValue?=?0;

    let?metric?=?{

    ??value:?0

    }

    new?PerformanceObserver(entryList?=>?{

    ??for?(const?entry?of?entryList.getEntries())?{

    ????if?(!entry.hadRecentInput)?{

    ??????const?firstSessionEntry?=?sessionEntries[0];

    ??????const?lastSessionEntry?=?sessionEntries[sessionEntries.length?-?1];



    ??????//?如果時(shí)間靠近上一個(gè)?session,?將本輪?layout-shift?累加進(jìn)上一個(gè)?session

    ??????if?(sessionValue?&&

    ??????????entry.startTime?-?lastSessionEntry.startTime?
    ??????????entry.startTime?-?firstSessionEntry.startTime?
    ????????sessionValue?+=?entry.value;

    ????????sessionEntries.push(entry);

    ??????}?else?{?//?新起一個(gè)?session

    ????????sessionValue?=?entry.value;

    ????????sessionEntries?=?[entry];

    ??????}



    ??????//?如果當(dāng)前?session?的?value?大于之前的最大值,替換為現(xiàn)在這個(gè)大的

    ??????if?(sessionValue?>?metric.value)?{

    ????????metric.value?=?sessionValue;

    ????????metric.entries?=?sessionEntries;

    ????????console.log('CLS:?',?metric)

    ??????}

    ????}

    ??}

    }).observe({

    ????type:?'layout-shift',

    ????buffered:?true

    });

    完整代碼見(jiàn)?? https://github.com/GoogleChrome/web-vitals/blob/main/src/getCLS.ts

    Long Tasks API[8] & Resource Timing API[9]

    TTI 的采集依賴這兩個(gè) API,計(jì)算過(guò)程:

    1. 先采集 FCP,作為起點(diǎn)
    2. 沿時(shí)間軸正向搜索時(shí)長(zhǎng)至少為 5 秒的安靜窗口(安靜窗口:沒(méi)有 Long Task 且不超過(guò)兩個(gè)正在處理的網(wǎng)絡(luò) GET 請(qǐng)求)
    3. 沿時(shí)間軸反向搜索安靜窗口之前的最后一個(gè)長(zhǎng)任務(wù),如果沒(méi)有找到長(zhǎng)任務(wù),則在 FCP 步驟停止執(zhí)行
    4. TTI 是安靜窗口之前最后一個(gè)長(zhǎng)任務(wù)的結(jié)束時(shí)間,如果沒(méi)有找到長(zhǎng)任務(wù),則與 FCP 值相同

    —— Time to Interactive (TTI)[10]

    54492a08e3c4ad1c10779f82628273cf.webp

    Mutation[11][12]Observer[13]

    收集 FMP:通過(guò) MutationObserver 對(duì) DOM 變化進(jìn)行監(jiān)聽(tīng),每次回調(diào)根據(jù)新舊 DOM 數(shù)量、種類(lèi)、深度等,計(jì)算出當(dāng)前 DOM 樹(shù)的分?jǐn)?shù),分?jǐn)?shù)變化最劇烈的時(shí)刻視為 FMP ,Load 事件觸發(fā)后 200ms 停止監(jiān)聽(tīng),取最大變動(dòng)的記錄做上報(bào)。

    new?MutationObserver(()?=>?{

    ??//?這里是劇烈程度分的計(jì)算

    }).observe(document,?{

    ??childList:?true,

    ??subtree:?true,

    });

    業(yè)界性能指標(biāo)采集工具

    In the Lab

    • Chrome DevTools[14]
    • Lighthouse[15]
    • WebPageTest[16]

    In the Field

    • web-vitals[17]
    參考

    Web Vitals[18]

    Largest Contentful Paint (LCP)[19]

    Cumulative Layout Shift (CLS)[20]

    First Input Delay (FID)[21]

    Measure performance with the RAIL model[22]

    參考資料

    [1]

    Performance Observer: https://www.w3.org/TR/performance-timeline-2/

    [2]

    Paint Timing API: https://w3c.github.io/paint-timing/#sec-PerformancePaintTiming

    [3]

    Largest Contentful Paint API: https://wicg.github.io/largest-contentful-paint/

    [4]

    Event Timing API: https://wicg.github.io/event-timing/

    [5]

    Navigation Timing 1.0: https://www.w3.org/TR/navigation-timing/

    [6]

    Navigation Timing 2.0: https://www.w3.org/TR/navigation-timing-2/

    [7]

    Layout Instability API: https://wicg.github.io/layout-instability/

    [8]

    Long Tasks API: https://www.w3.org/TR/2017/WD-longtasks-1-20170907/

    [9]

    Resource Timing API: https://www.w3.org/TR/resource-timing-2/

    [10]

    Time to Interactive (TTI): https://web.dev/tti/

    [11]

    Mutation: https://dom.spec.whatwg.org/#mutationobserver

    [12]

    : https://dom.spec.whatwg.org/#mutationobserver

    [13]

    Observer: https://dom.spec.whatwg.org/#mutationobserver

    [14]

    Chrome DevTools: https://developers.google.com/web/tools/chrome-devtools/

    [15]

    Lighthouse: https://developers.google.com/web/tools/lighthouse/

    [16]

    WebPageTest: https://www.webpagetest.org/

    [17]

    web-vitals: https://github.com/GoogleChrome/web-vitals

    [18]

    Web Vitals: https://web.dev/vitals/

    [19]

    Largest Contentful Paint (LCP): http://web.dev/lcp

    [20]

    Cumulative Layout Shift (CLS): https://web.dev/cls/

    [21]

    First Input Delay (FID): https://web.dev/fid/

    [22]

    Measure performance with the RAIL model: https://web.dev/rail/


    往期推薦

    React 全局狀態(tài)管理的 3 種底層機(jī)制

    深入對(duì)比 eslint 插件 和 babel 插件的異同點(diǎn)

    六個(gè)問(wèn)題讓你更懂 React Fiber,了解框架底層渲染邏輯

    一文速覽 TypeScript 裝飾器 與 IoC 機(jī)制

    你不知道 CSS 可以做的 4 件事

    點(diǎn)擊下方“技術(shù)漫談”,選擇“設(shè)為星標(biāo)
    第一時(shí)間關(guān)注技術(shù)干貨!
    瀏覽 137
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

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

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    欧美日韩国产在线播放 | 国产性爱69 | 女公安一级毛片陆放 | 中文一级久久黄色 | 青娱乐人人干 |