传统性能规范


初始化阶段

  • 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

    各个阶段计算形式


    页面加载总工夫
    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

    以用户为核心的性能指标

    传统的性能指标,比拟关注技术细节;疏忽用户所真正关怀的指标;如果仅仅只是页面加载很快,但用户体验很差,也是不行的。

    FP & FCP


    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

First Meaning Paint,首次要害内容绘制,指浏览器渲染出第一个要害内容的工夫。不过“要害内容”是难有一个明确定义的,依据利用不同其要害内容也是不一样的
FMP 通常也被用来掂量首屏工夫。不过 FMP 的计算过于简单,所以无奈应用 API 间接获取,就算计算出来了也不肯定就精确,所以连 Lighthouse 在 6.0 版本之后都不再计算这个指标了,取而代之的是 LCP。



TTI



Time to Interactive,可交互工夫,该指标用于测量页面从开始加载到次要子资源实现渲染,并可能疾速、牢靠地响应用户输出所需的工夫。简略的讲,TTI 是宁静窗口之前最初一个长工作(超过 50 毫秒的工作)的完结工夫(如果没有找到长工作,则与 FCP 值雷同)
TTI 工夫如果在

  1. 0-3.8 秒之间就是一个比拟优良的指标;
  2. 3.9-7.3 秒之间就比拟中等了,略微有点儿慢;
  3. 超过 7.3 秒就是十分慢了。

    FID


    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


Total Blocking Time,总阻塞工夫,指 FCP 与 TTI 之间的总工夫,这期间,主线程被阻塞的工夫过长,无奈做出输出响应。工作持续时间小于 50 毫秒的阻塞工夫记为 0,超过 50 毫秒的工作阻塞工夫就是这个工作执行的工夫减去 50 毫秒失去的工夫,一个页面的总阻塞工夫是在 FCP 和 TTI 之间产生的每个长工作(超过 50 毫秒的工作)的阻塞工夫总和。
TBT 工夫如果在

  1. 0-200 毫秒之间就是一个比拟优良的指标;
  2. 200-600 毫秒之间就比拟中等了,略微有点儿慢;
  3. 超过 600 毫秒就是十分慢了

    LCP


    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


    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 就是十分不稳固了。

    总结


    参考:

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