9
头图

传统性能标准

截屏2022-12-11 下午9.27.15.png截屏2022-12-11 下午9.27.55.png

初始化阶段

  • navigationStart:请求开始时间,返回 0
  • unloadEventStart:等于用户代理程序开始前一个文档的卸载事件之前的时间
  • unloadEventEnd:等于用户代理程序完成前一文档的卸载事件之后的时间
  • redirectStart:重定向开始时间的时间戳,没发生则为 0
  • redirectEnd:重定向完成时间的时间戳,没发生则为 0

    请求阶段

  • fetchStart:表征了浏览器准备好使用 HTTP 请求来获取(fetch)文档的时间戳,这个时间点会在检查任何应用缓存之前
  • domainLookupStart:是一个无符号long long 型的毫秒数,表征了域名查询开始的UNIX时间戳。如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和 PerformanceTiming.fetchStart 一致。
  • domainLookupEnd:是一个无符号long long 型的毫秒数,表征了域名查询结束的UNIX时间戳。如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和 PerformanceTiming.fetchStart 一致。
  • connectStart:请求连接被发送到网络之时的Unix毫秒时间戳。如果传输层报告错误并且连接的建立重新开始,则把最后建立连接的开始时间作为该值。如果一个持久连接被使用,则该值与 PerformanceTiming.fetchStart 相同。
  • secureConnectionStart:为安全连接握手开始的时刻的 Unix毫秒时间戳。如果只要你过的连接没有被请求,则它返回 0。
  • connectEnd:代表了网络链接建立的时间节点。如果传输层报告了错误或者链接又被重新建立,则采用最后一次链接建立的时间。如果链接是长久的,那么这个值等同于 PerformanceTiming.fetchStart。链接被认为打开以所有的链接握手,SOCKS认证结束为标志。
  • requestStart:为浏览器发送从服务器或者缓存获取实际文档的请求之时的 Unix毫秒时间戳。如果传输层在请求开始之后发生错误并且连接被重新打开,则该属性将会被设定为新的请求的相应的值 。
  • responseStart:为浏览器从服务器、缓存或者本地资源接收到响应的第一个字节之时的 Unix毫秒时间戳。
  • responseEnd:为浏览器从服务器、缓存或者本地资源接收响应的最后一个字节或者连接被关闭之时的 Unix毫秒时间戳

    解析渲染阶段

  • domLoading:返回当前网页 DOM 结构开始解析时
  • domInteractive:为在主文档的解析器结束工作,即 Document.readyState 改变为 'interactive' 并且相当于 readystatechange (en-US) 事件被触发之时的 Unix毫秒时间戳。
  • domContentLoadedEventStart:为解析器发出 DOMContentLoaded 事件之前,即所有的需要被运行的脚本已经被解析之时的 Unix毫秒时间戳。
  • domContentLoadedEventEnd:这个时刻为所有需要尽早执行的脚本不管是否按顺序,都已经执行完毕,即 DOM Ready
  • domComplete:为主文档的解析器结束工作,Document.readyState 变为 'complete'且相当于readystatechange 事件被触发时的 Unix毫秒时间戳。
  • loadEventStart:为 load 事件被现在的文档触发之时的 Unix时间戳。如果这个事件没有被触发,则他返回 0。
  • loadEventEnd:为 load 事件处理程序被终止,加载事件已经完成之时的 Unix毫秒时间戳。如果这个事件没有被触发,或者没能完成,则该值将会返回0

    各个阶段计算方式

    截屏2022-12-11 下午9.29.33.png
    页面加载总时间
    loadEventEnd - startTime
    onload事件触发
    DNS解析时间
    domainLookupEnd - domainLookupStart
    TCP连接耗时
    connectEnd - connectStart
    SSL连接耗时
    connectEnd - secureConnectionStart
    https 协议才有
    网路请求耗时
    responseStart - requestStart
    数据传输耗时
    responseEnd-responseStart
    DOM解析耗时
    domContentLoadedEventEnd - responseEnd
    资源加载耗时
    loadEventEnd - domContentLoadedEventEnd
    页面渲染耗时
    loadEventEnd - responseEnd
    页面完全加载时间
    loadEventEnd - startTime
    HTML加载完时间
    responseEnd - startTime
    首次可交互时间
    domInteractive - startTime

    以用户为中心的性能指标

    传统的性能指标,比较关注技术细节;忽略用户所真正关心的指标;如果仅仅只是页面加载很快,但用户体验很差,也是不行的。
    截屏2022-12-11 下午9.33.37.png

    FP & FCP

    截屏2022-12-11 下午9.34.16.png
    First Paint 首次绘制,指浏览器从开始请求网站内容(导航阶段)到首次向屏幕绘制像素点的时间,刚到 Painting 阶段(如下图所示),所以 FP 也可以理解为是白屏时间。

    // 更推荐使用 Promise 封装获取
    const observerWithPromise = new Promise<PerformanceObserverEntryList>((resolve, reject) => {
    new PerformanceObserver(resolve).observe({
      entryTypes: ['paint'],
    });
    });
      
    observerWithPromise
    .then(entryList => {
      return entryList.getEntries().filter(entry => {
        return entry.name === 'first-paint';
      })[0];
    })
    .then(entry => console.log(entry.startTime));

    First Contentful Paint,首次内容绘制,指浏览器渲染出第一个内容的时间,内容可以是文本、img标签、SVG元素等,但是不包括 iframe 和白色背景的 Canvas 元素

    // 更推荐使用 Promise 封装获取
    const observerWithPromise = new Promise<PerformanceObserverEntryList>((resolve, reject) => {
    new PerformanceObserver(resolve).observe({
      entryTypes: ['paint'],
    });
    });
      
    observerWithPromise
    .then(entryList => {
      return entryList.getEntries().filter(entry => {
        return entry.name === 'first-contentful-paint';
      })[0];
    })
    .then(entry => console.log(entry.startTime));

    FCP 时间如果在

  1. 0-1.8 秒之间就是一个比较优秀的指标;
  2. 1.8-3.0 秒之间就比较中等了,稍微有点儿慢;
  3. 超过 3 秒就是非常慢了

    FMP & SI

    截屏2022-12-11 下午9.34.35.png

First Meaning Paint,首次关键内容绘制,指浏览器渲染出第一个关键内容的时间。不过“关键内容”是难有一个明确定义的,根据应用不同其关键内容也是不一样的
FMP 通常也被用来衡量首屏时间。不过 FMP 的计算过于复杂,所以无法使用 API 直接获取,就算计算出来了也不一定就准确,所以连 Lighthouse 在 6.0 版本之后都不再计算这个指标了,取而代之的是 LCP。

截屏2022-12-11 下午9.35.09.png
截屏2022-12-11 下午9.34.55.png

TTI

截屏2022-12-11 下午9.35.22.png
截屏2022-12-11 下午9.35.38.png
Time to Interactive,可交互时间,该指标用于测量页面从开始加载到主要子资源完成渲染,并能够快速、可靠地响应用户输入所需的时间。简单的讲,TTI 是安静窗口之前最后一个长任务(超过 50 毫秒的任务)的结束时间(如果没有找到长任务,则与 FCP 值相同)
TTI 时间如果在

  1. 0-3.8 秒之间就是一个比较优秀的指标;
  2. 3.9-7.3 秒之间就比较中等了,稍微有点儿慢;
  3. 超过 7.3 秒就是非常慢了。

    FID

    截屏2022-12-11 下午9.35.53.png
    First Input Delay ,首次输入延迟,测量从用户第一次与页面交互(例如当他们单击链接、点按按钮或使用由 JavaScript 驱动的自定义控件)直到浏览器对交互作出响应,并实际能够开始处理事件处理程序所经过的时间,FID 是衡量交互性的核心指标

    const observerWithPromise = new Promise<PerformanceObserverEntryList>((resolve, reject) => {
    new PerformanceObserver(resolve).observe({
      entryTypes: ['first-input'],
    });
      });
      observerWithPromise
    .then(entryList => {
      for (const entry of entryList.getEntries()) {
        // eslint-disable-next-line no-undef
        const delay = (entry as PerformanceEventTiming).processingEnd - entry.startTime;
        console.log(delay);
      }
    });

    FID 时间如果在

  4. 0-100 毫秒之间就是一个比较优秀的指标;
  5. 100-300 毫秒之间就比较中等了,稍微有点儿慢;
  6. 超过 300 毫秒就是非常慢了

TBT

截屏2022-12-11 下午9.36.36.png
Total Blocking Time,总阻塞时间,指 FCP 与 TTI 之间的总时间,这期间,主线程被阻塞的时间过长,无法做出输入响应。任务持续时间小于 50 毫秒的阻塞时间记为 0,超过 50 毫秒的任务阻塞时间就是这个任务执行的时间减去 50 毫秒得到的时间,一个页面的总阻塞时间是在 FCP 和 TTI 之间发生的每个长任务(超过 50 毫秒的任务)的阻塞时间总和。
TBT 时间如果在

  1. 0-200 毫秒之间就是一个比较优秀的指标;
  2. 200-600 毫秒之间就比较中等了,稍微有点儿慢;
  3. 超过 600 毫秒就是非常慢了

    LCP

    截屏2022-12-11 下午9.36.10.png
    Largest Contentful Paint,最大内容绘制,指可视区内容最大的可见元素出现在屏幕上的时间,

    const observerWithPromise = new Promise<PerformanceObserverEntryList>((resolve, reject) => {
     new PerformanceObserver(resolve).observe({
       entryTypes: ['largest-contentful-paint'],
     });
      });
      observerWithPromise
     .then(entryList => {
       const entries = entryList.getEntries();
       const lastEntry = entries[entries.length - 1];
       console.log(lastEntry.startTime);
     });

    LCP 时间如果在

  4. 0-2.5 秒之间就是一个比较优秀的指标;
  5. 2.5-4 秒之间就比较中等了,稍微有点儿慢;
  6. 超过 4 秒就是非常慢了

    CLS

    截屏2022-12-11 下午9.36.55.png
    Cumulative Layout Shift,累积布局偏移,测量整个页面生命周期内发生的所有意外布局偏移中最大一连串的布局偏移分数。
    简单的讲就是页面因为一些动态改变的 DOM 或者一些异步的资源加载,导致页面元素发生了位移,这样就会让用户找不到先前阅读的位置或者点击到不期望点击的地方。

    let clsValue = 0;
    let clsEntries = [];
    
    let sessionValue = 0;
    let sessionEntries: PerformanceEntry[] = [];
    const observerWithPromise = new Promise<PerformanceObserverEntryList>((resolve, reject) => {
      new PerformanceObserver(resolve).observe({
     entryTypes: ['layout-shift'],
      });
    });
    observerWithPromise
      .then(entryList => {
     for (const entry of entryList.getEntries()) {
       // 只将不带有最近用户输入标志的布局偏移计算在内。
       // @ts-ignore
       if (!entry.hadRecentInput) {
         const firstSessionEntry = sessionEntries[0];
         const lastSessionEntry = sessionEntries[sessionEntries.length - 1];
    
         // 如果条目与上一条目的相隔时间小于 1 秒且
         // 与会话中第一个条目的相隔时间小于 5 秒,那么将条目
         // 包含在当前会话中。否则,开始一个新会话。
         if (sessionValue &&
             entry.startTime - lastSessionEntry.startTime < 1000 &&
             entry.startTime - firstSessionEntry.startTime < 5000) {
           // @ts-ignore
           sessionValue += entry.value;
           sessionEntries.push(entry);
         } else {
           // @ts-ignore
           sessionValue = entry.value;
           sessionEntries = [entry];
         }
    
         // 如果当前会话值大于当前 CLS 值,
         // 那么更新 CLS 及其相关条目。
         if (sessionValue > clsValue) {
           clsValue = sessionValue;
           clsEntries = sessionEntries;
    
           // 将更新值(及其条目)记录在控制台中。
           console.log('CLS:', clsValue, clsEntries);
         }
       }
     }
      });

    CLS 如果在

  7. 0-0.1 之间就会有一个比较好的稳定性;
  8. 0.1-0.25 之间就比较中等了;
  9. 超过 0.25 就是非常不稳定了。

    总结

    截屏2022-12-11 下午9.37.19.png
    参考:

  10. https://web.dev/metrics/
  11. https://juejin.cn/post/7104310605091176456#heading-2

散一群逗逼
554 声望508 粉丝

做一位有逼格的前端工程师