Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

页面性能指标计算方式 #228

Open
funnycoderstar opened this issue Feb 7, 2023 · 0 comments
Open

页面性能指标计算方式 #228

funnycoderstar opened this issue Feb 7, 2023 · 0 comments

Comments

@funnycoderstar
Copy link
Owner

funnycoderstar commented Feb 7, 2023

Web Vitals

白屏时间(FP)

概念:又称为首次渲染时间。从用户打开页面开始,到第一次渲染出可见元素为止。即标记浏览器渲染任何在视觉上不同于导航前屏幕内容的时间点。
收集方式:

  1. 可以通过 window.performance.timing
// 白屏时间(FP) = 页面开始展示的时间点 - 开始请求的时间点
blankTime = performance.timing.responseStart - performance.timing.fetchStart;

上面这种计算方式认为白屏时间是页面返回的首字节时间,但这样其实并不精准,因为头部资源还没加载完毕,页面也是白屏。
可以通过 domLoading - fetchStart来获取,此时页面开始解析 DOM 树,页面渲染的第一个元素也会很快出现

//白屏时间
blankTime = (t.domInteractive || t.domLoading) - t.fetchStart;
  1. performance.getEntriesByName('first-paint')[0]
// FP
let FP = performance.getEntriesByName('first-paint')[0].startTime;

这种方式收集出现的问题是:

疑问:白屏时间和首次渲染时间(FP)是一个概念么?

FCP(First Contentful Paint)

FP 指的是绘制像素,比如说页面的背景色是灰色的,那么在显示灰色背景时就记录下了 FP 指标。但是此时 DOM 内容还没开始绘制,可能需要文件下载、解析等过程,只有当 DOM 内容发生变化才会触发,比如说渲染出了一段文字,此时就会记录下 FCP 指标。因此说我们可以把这两个指标认为是和白屏时间相关的指标,所以肯定是最快越好。

首次内容绘制,标记浏览器渲染来自 DOM 第一位内容的时间点,内容可能是文本,图像等元素

收集方式:

  1. performance.getEntriesByName('first-contentful-paint')[0]
// FCP
let FCP = performance.getEntriesByName('first-contentful-paint')[0].startTime;

首屏时间

概念:HTML 文档加载解析完成的时间点。
重要原因:
收集方式:

  • 页面标签标记法
  • 图像相似度比较法
  • 首屏高度内图片加载法;通过寻找首屏区域内的所有图片,计算他们加载完的时间去得到首屏时间

一般的页面加载流程:HTTP 请求 → HTML 文档加载解析完成 → 加载样式和脚本文件 → 完成页面渲染。而要采集这个首屏时间,可以用浏览器提供的 DOMContentLoaded 接口来实现,具体的思路是

  1. 可以通过 window.performance.timing
// *: 首屏时间
timingInfo.domContentLoadedEventEnd - timingInfo.fetchStart;

这种方式收集出现的问题是:
如果是单页应用的话,统计不准确。原因是因为,单页应用中,整体的加载流程是:

用户请求一个页面时,页面会先加载 index.html,加载完成后,就会触发 DOMContentLoaded 和 load。而这个时候,页面展示的只是个空白页。此时根本不算真正意义的首屏。接下来,页面会加载相关脚本资源并通过 axios 异步请求数据,使用数据渲染页面主题部分,这个时候首屏才渲染完成。

单页应用可以使用 MutationObserver 采集首屏时间。

FMP

概念:首次有效绘制,是指首次绘制对用户有用内容的时间点。有用的内容,是指 Youtube 上的视频;Twitter 上的推文;天气应用中的天气预测......这些内容或元素,也被称为主角元素 (Hero Elements) ,能够向用户提供有用的内容。但是这些元素难以界定,所以后来用 LCP 来取代 FMP。

收集方式

// 需要指定一个有意义的元素
setTimeout(() => {
    let h1 = document.createElement('h1');
    h1.innerHTML = '我是这个页面中最有意义的内容';
    // 指定该属性,表示为有意义的元素
    h1.setAttribute('elementtiming', 'meaningful');
    document.body.appendChild(h1);
}, 2000);

let FMP;
// 增加一个性能条目的观察者
new PerformanceObserver((entryList, observer) => {
    console.log('hahahah');
    // entryList 观察的条目
    let perfEntries = entryList.getEntries();
    console.log(111, perfEntries);
    // FMP需要自己指定一个有意义的元素
    FMP = perfEntries[0];
    observer.disconnect();
}).observe({ entryTypes: ['element'] }); // 观看页面中有意义的条目

TTFB(Time to First Byte)

概念:首字节到达的时间点。

意义: 这可以理解为用户拿到你的资源占用的时间,加异地机房了么,加 CDN 处理了么?加带宽了么?加 CPU 运算速度了么?
收集方式:

  1. 通过 performance.timing
// TTFP: 首字节时间
const ttfbTime = performance.timing.responseEnd - performance.timing.requestStart;

LCP(Largest Contentful Paint)

概念:最大内容绘制时间,计算从页面开始加载到用户与页面发生交互(点击,滚动)这段时间内,最大元素绘制的时间,该时间会随着页面渲染变化而变化,因为页面中的最大元素在渲染过程中可能会发生改变。

new PerformanceObserver((entryList, observer) => {
    // entryList 观察的条目
    let perfEntries = entryList.getEntries();
    LCP = perfEntries[0];
    observer.disconnect();
}).observe({ entryTypes: ['largest-contentful-paint'] }); // 观看页面中最大有意义的条目

FID(First Input Delay)

概念:首次输入延迟,指用户首次输入到页面响应的时间。我们都知道第一印象的重要性,网站亦是如此。首次输入延迟会成为用户对网站很重要的第一印象,决定用户有可能成为忠实用户或者弃之而去。值得注意的是,FID 仅关注用户离散的操作,如点击,轻击,按键等,其他交互如滚动和缩放,并不是 FID 关注的,因为通常浏览器会用一个单独的线程来处理它们。

const FIDTime = performance.getEntriesByType('first-input')[0].startTime;
// FID
new PerformanceObserver((entryList, observer) => {
    let firstInput = entryList.getEntries()[0];
    if (firstInput) {
        // processingStart 开始处理的时间,startTime开始点击的时间 差值就是处理的延迟
        let inputDelay = firstInput.processingStart - firstInput.startTime;

        let dutation = firstInput.duration; // 处理的耗时
        if (inputDelay > 0 || dutation > 0) {
            const performanceLog = {
                kind: 'experience',
                type: 'firstInputDelay', // 首次输入延迟
                inputDelay,
                duration,
                startTime: firstInput.startTime,
            };
        }
    }
    observer.disconnect();
}).observe({ type: 'first-input', buffered: true });
<input type="button" value="点我" onclick="testFID()" />;
function testFID() {
    console.log(1111);
}

CLS

Cumulative Layout Shift 累计布局位移 (衡量网页元件视觉稳定性)

let cls = 0;
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

Core Web Vitals

https://web.dev/learn-core-web-vitals/

@funnycoderstar funnycoderstar changed the title 页面核心性能指标如何计算 页面性能指标如何计算? Feb 7, 2023
@funnycoderstar funnycoderstar changed the title 页面性能指标如何计算? 页面性能指标计算方式 Feb 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant