性能优化 - 前端性能监控和性能指标计算方式

性能优化 - 前端性能监控和性能指标计算方式

  • 前言
  • 一. 性能指标介绍
    • 1.1 单一指标介绍
    • 1.2 指标计算
      • ① Redirect(重定向耗时)
      • ② AppCache(应用程序缓存的DNS解析)
      • ③ DNS(DNS解析耗时)
      • ④ TCP(TCP连接耗时)
      • ⑤ TTFB(请求响应耗时)
      • ⑥ Trans(内容传输耗时)
      • ⑦ DOM(DOM解析耗时)
    • 1.3 FP(first-paint) 和 FCP(first-contentful-paint)
    • 1.4 LCP(Largest Contentful Paint)
    • 1.5 LongTask长任务统计
  • 二. 性能指标计算测试
    • 2.1 衡量网络请求响应时间的指标
    • 2.2 衡量页面加载速度的指标
    • 2.3 TTI(Time to Interactive)衡量页面可交互性的指标
    • 2.4 TBT(Total Blocking Time)
    • 2.5 总结

前言

利用LightHouse进行合理的页面性能优化 这篇文章主要讲解了如何使用Lighthouse。 这里把相关图片再展示一下:
在这里插入图片描述
我们可以看到Lighthouse计算的时候,会根据这几个维度的指标来计算总分。那么本篇文章,就主要讲解下前端性能监控相关的重要指标含义和计算方式。

一. 性能指标介绍

在介绍指标之前,我们首先应当知道这些数据可以从哪里获取。JS里面,有一个 performance 对象,它是专门用来用于性能监控的对象,内置了一些前端需要的性能参数。

我们随便打开一个浏览器,在终端控制台输入以下内容:

performance.getEntriesByType('navigation')

如图:
在这里插入图片描述

1.1 单一指标介绍

  1. navigationStart:导航开始的时间,即浏览器开始获取页面的时间。
  2. redirectCount:重定向次数,表示在导航过程中发生的重定向次数。
  3. type:导航类型,可能的取值有:
    • navigate:常规导航,例如用户点击链接或输入URL进行的导航。
    • reload:页面重新加载。
    • back_forward:通过浏览器的前进或后退按钮导航。
  4. unloadEventStart:前一个页面的unload事件开始的时间。
  5. unloadEventEnd:前一个页面的unload事件结束的时间。
  6. redirectStart:重定向开始的时间。
  7. redirectEnd:重定向结束的时间。
  8. fetchStart:浏览器开始获取页面资源的时间。
  9. domainLookupStart:域名解析开始的时间。
  10. domainLookupEnd:域名解析结束的时间。
  11. connectStart:建立与服务器连接开始的时间。
  12. connectEnd:建立与服务器连接结束的时间。
  13. secureConnectionStart:安全连接开始的时间,如果不是安全连接,则该值为0。
  14. requestStart:向服务器发送请求的时间。
  15. responseStart:接收到服务器响应的时间。
  16. responseEnd:接收到服务器响应并且所有资源都已接收完成的时间。
  17. domLoading:开始解析文档的时间。
  18. domInteractive:文档解析完成并且所有子资源(例如图片、样式表等)也已加载完成的时间。
  19. domContentLoadedEventStartDOMContentLoaded事件开始的时间,表示HTML文档解析完成并且所有脚本文件已下载完成。
  20. domContentLoadedEventEndDOMContentLoaded事件结束的时间,表示所有脚本文件已执行完成。
  21. domComplete:文档和所有子资源(例如图片、样式表等)都已完成加载的时间。
  22. loadEventStartload事件开始的时间,表示所有资源(包括图片、样式表、脚本文件等)都已加载完成。
  23. loadEventEndload事件结束的时间,表示所有资源(包括图片、样式表、脚本文件等)都已执行完成。

1.2 指标计算

我们看下图
在这里插入图片描述

我们从上图出发,分别对各个阶段进行计算,我们说下几个比较重要的阶段,按照从左往右的顺序。

① Redirect(重定向耗时)

表示从重定向开始(redirectStart)到重定向结束的时间(redirectEnd)的时间间隔,它反映了浏览器在这段时间内完成了重定向的过程:

const redirectTime = redirectEnd - redirectStart

② AppCache(应用程序缓存的DNS解析)

这一部分也是在进行DNS解析,在使用AppCache(应用程序缓存)的情况下,浏览器会在加载页面时检查缓存中是否存在相应的资源,并根据需要更新缓存:

const appcacheTime = domainLookupStart - fetchStart

③ DNS(DNS解析耗时)

DNS解析耗时:在浏览器加载网页时,当需要与服务器建立连接时,浏览器会首先进行DNS解析,将域名转换为对应的IP地址。DNS解析的过程包括向DNS服务器发送查询请求、等待DNS服务器响应以及获取到IP地址。

dns = domainLookupEnd - domainLookupStart

④ TCP(TCP连接耗时)

TCP连接耗时:在浏览器加载网页时,当浏览器需要与服务器建立连接时,它会向服务器发送请求,并等待服务器响应。建立连接的过程包括TCP握手、SSL握手等。

tcp = connectEnd - connectStart

其中还有建立SSL连接的时间,包括在TCP耗时里面。

ssl = connectEnd - secureConnectionStart

⑤ TTFB(请求响应耗时)

请求耗时:从发送请求到接收到服务器响应的第一个字节所花费的时间。

ttfb = responseStart - requestStart

⑥ Trans(内容传输耗时)

当浏览器发送请求后,服务器会返回相应的响应,这个差值就是衡量浏览器接收服务器响应的耗时。

trans = responseEnd - responseStart

⑦ DOM(DOM解析耗时)

DOM这一块比较复杂,实际上还能分成3个小DOM阶段。

  1. 阶段一(注意,上图中并没有显式地展示出来):解析DOM阶段。
const dom1 = domInteractive - responseEnd
  1. 阶段二:文档解析完成,html、js解析完成,css、图片加载完成。即加载DOM阶段。
const dom2 = domComplete-domInteractive
  1. 阶段二当中还可以分出一小个阶段:代表从开始加载DOM内容到DOM内容加载完成的时间间隔。
const domLoaded = domContentLoadedEventEnd - domContentLoadedEventStart

1.3 FP(first-paint) 和 FCP(first-contentful-paint)

FP(first-paint)FCP(first-contentful-paint)

FP指的是浏览器首次将像素渲染到屏幕上的时间点,即页面开始渲染的时间点。通常情况下,FP是指浏览器首次绘制任何可见的内容,包括背景色、文字、图片等,但不包括用户界面的控件,比如滚动条、按钮等。

FCP指的是浏览器首次将页面的有意义的内容渲染到屏幕上的时间点,即页面开始呈现有意义的内容的时间点。有意义的内容可以是文本、图片、视频等,但不包括背景色、边框等无意义的内容。

一般情况下,两者基本上没有什么区别,来说下两者的获取方式:

const fp = performance.getEntriesByName('first-paint')[0].startTime
const fcp = performance.getEntriesByName('first-contentful-paint')[0].startTime

后面我们都只说FCP

1.4 LCP(Largest Contentful Paint)

FCP: First Contentful Paint首次内容绘制是指测量页面从开始加载到页面内容(文本、图片、背景图、svg 元素或非白色 canvas 元素)的任何部分在屏幕上完成渲染的时间,是测量加载速度感知的重要指标之一。

获取方式,我们主要通过Performance 来进行监听:

new PerformanceObserver((entryList) => {var maxSize = 0;var renderTime = 0;for (var entry of entryList.getEntries()) {// 渲染的内容看最大值if(entry.size > maxSize){maxSize = entry.size;renderTime = entry.startTime;}}console.log('LCP', renderTime)
}).observe({type: 'largest-contentful-paint', buffered: true});

1.5 LongTask长任务统计

LongTask(长任务)是指在JavaScript主线程上执行时间超过50毫秒的任务。这些任务可能是复杂的计算、大量数据处理、DOM操作或其他耗时的操作。

我们可以通过以下方式来获取:

new PerformanceObserver((entryList) => {var list = entryList.getEntries();var entry = list[list.length-1];if(entry){console.log('LongTask',entry.startTime)}
}).observe({type: 'longtask', buffered: true});

一般我们取最后一个就是长任务的总耗时。这个值越低,性能越高。

二. 性能指标计算测试

贴出案例代码:

function test() {const entry = performance.getEntriesByType('navigation')[0]const {domComplete, secureConnectionStart, domInteractive, domContentLoadedEventStart, domainLookupEnd,domainLookupStart, connectEnd, connectStart, responseStart, requestStart, responseEnd, loadEventStart, domContentLoadedEventEnd, fetchStart, redirectEnd, redirectStart} = entry// redirectTimeconst redirectTime = redirectEnd - redirectStart// appcacheTimeconst appcacheTime = domainLookupStart - fetchStart// DNS解析时间const dnsTime = domainLookupEnd - domainLookupStart// TCP建立时间const tcpTime = connectEnd - connectStart// ssl 时间const sslTime = connectEnd - secureConnectionStart// requestTime 读取页面第一个字节的时间(请求时间)const requestTime = responseStart - requestStart// 返回响应时间const responseTime = responseEnd - responseStart// domContentLoadedEventEnd - domContentLoadedEventStartconst domLoaded = domContentLoadedEventEnd - domContentLoadedEventStart// loadEventEnd - loadEventStartconst loadTime = loadEventStart - domContentLoadedEventEndconst dom1 = domInteractive - responseEnd// 解析dom树耗时const dom2 = domComplete - domInteractiveconsole.log('********各个阶段的消耗耗时********')console.log('redirectTime', redirectTime)console.log('appcacheTime', appcacheTime)console.log('dnsTime', dnsTime)console.log('tcpTime', tcpTime, '其中包括ssl时间', sslTime)console.log('TTFB(请求响应耗时)', requestTime)console.log('Trans(内容传输耗时)', responseTime)console.log('解析`DOM`阶段', dom1)console.log('加载`DOM`阶段', dom2, '其中包括(domContentLoadedEventEnd - domContentLoadedEventStart)', domLoaded)console.log('load事件耗时', loadTime)console.log('********校验时间差********')console.log('***********校验 responseStart - fetchStart差值**************');console.log('responseStart - fetchStart', responseStart - fetchStart)console.log('appCache + dns+ tcp + requestTime 总和:', appcacheTime + dnsTime + tcpTime + requestTime)console.log('***********校验 domInteractive - fetchStart差值**************');const tmp = appcacheTime + dnsTime + tcpTime + requestTime + responseTimeconst diff = domInteractive - fetchStartconsole.log('domInteractive - fetchStart', diff)console.log( 'appCache + dns+ tcp + request + response, 总和:', tmp, ', 空白时间', diff - tmp)console.log('空白时间(就是文档解析和构建DOM树的过程),即DOM1(domInteractive - responseEnd)', dom1)// 算一下domCompelete - fetchStartconsole.log('domCompelete - fetchStart', domComplete - fetchStart)console.log('********FCP********')const fcp = performance.getEntriesByName('first-contentful-paint')[0].startTimeconsole.log("LCP(通过performance.getEntriesByName('first-contentful-paint')计算出来的)", fcp)console.log('********LCP********')new PerformanceObserver((entryList) => {var maxSize = 0;var renderTime = 0;for (var entry of entryList.getEntries()) {// 渲染的内容看最大值if (entry.size > maxSize) {maxSize = entry.size;renderTime = entry.startTime;}}console.log('LCP', renderTime)}).observe({ type: 'largest-contentful-paint', buffered: true });console.log('********LongTask********')new PerformanceObserver((entryList) => {var list = entryList.getEntries();var entry = list[list.length - 1];if (entry) {console.log('LongTask', entry.startTime)}}).observe({ type: 'longtask', buffered: true });
}

复制这段代码到浏览器中,然后运行test()即可,结果如下:(FCP打印错了)
在这里插入图片描述

代码里主要打印了各个阶段的耗时时长。我们主要看下下半部分的校验部分。再把上面的图搬过来对照着看:
在这里插入图片描述

2.1 衡量网络请求响应时间的指标

从发起网络请求(fetchStart)到服务器开始响应(responseStart)的时间间隔。

  • responseStart - fetchStart的差值为257毫秒。
  • 而这个差值由:appCache + dns+ tcp + requestTime 4个阶段连接而成,4个阶段的时间总和为256.5毫秒,基本上接近。

2.2 衡量页面加载速度的指标

从发起网络请求(fetchStart)到DOM解析完成(domInteractive)的时间间隔

  • domInteractive - fetchStart的差值为1328毫秒。
  • 而这个差值由:appCache + dns+ tcp + request + response + 空白时间 部分组成(空白时间就是上图的红色框部分)。
  • 我们可以看到,前5个区域的时间总和大概是:480毫秒。空白时间则848毫秒。
  • 我们又计算了domInteractive - responseEnd的差值,实际上就是DOM1,也就是加载DOM的时间,时间差为848毫秒,相吻合。

综上所述:

  • 页面加载速度的指标可以由:DNS+TCP+Request+Response+DOM加载完毕耗时 的总和来决定。

另外我们还能看出来,LCP的计算可以几乎为:domInteractive - fetchStart, 当然你用PerformanceObserver进行监听也是可以的。

这里代表页面加载速度,此时DOM仅仅是解析完成,如果想看DOM也加载完成的耗时,看指标domComplete - fetchStart

2.3 TTI(Time to Interactive)衡量页面可交互性的指标

TTI:表示从页面开始加载到用户可以与页面进行交互的时间。它的计算方式如下:

  1. FCP 时间为起始时间
  2. 查找到指示有5s的静默窗口时间(没有长任务并且不超过两个正在执行的GET请求)。
  3. 向后搜索静默窗口前的最后一个长任务,如果没有找到长任务,则在FCP上停止。
  4. TTI 是在安静窗口之前最后一个长任务的结束时间(如果没有找到长任务,则与FCP相同)

在这里插入图片描述

建议大家使用谷歌官方提供的:tti-polyfill

import ttiPolyfill from './path/to/tti-polyfill.js';ttiPolyfill.getFirstConsistentlyInteractive(opts).then((tti) => {// Use `tti` value in some way.
});

当然,也可以使用一种较为粗略的方式来计算:

  1. 首先我们理解一下TTI,是从页面开始加载到用户可以与页面进行交互的时间。
  2. 页面开始加载,我们是不是可以看做fetchStart的时间。
  3. 页面进行交互的时间,那这个时候dom肯定是加载完毕了。我们按照非常极限的思路去想,这个是不是可以看做dom加载完毕的时间点,即domComplete
  4. 那么TTI ≈ domComplete - fetchStart

例如我用Lighthouse计算出来的TTI
在这里插入图片描述
使用:domComplete - fetchStart 计算出来的值:

function getTTI(){const entry = performance.getEntriesByType('navigation')[0]const {domComplete,fetchStart} = entryconsole.log('TTI', domComplete - fetchStart)
}
getTTI()

结果如下:
在这里插入图片描述

2.4 TBT(Total Blocking Time)

TBT就是衡量从FCP时间点到TTI这个时间点的时间区间内,所有超过50毫秒的长任务的总耗时。(这个看下来难以通过编码的方式来实现计算,也无法预估)

2.5 总结

  1. 我们在为页面做性能监控的时候,LCPFCP是我们的几个重要关注对象。
  2. LCP可以通过PerformanceObserver进行检测。
  3. FCP可以通过performance.getEntriesByName('first-contentful-paint')[0].startTime获取。
  4. 页面性能的发部分数据都可以从performance.getEntriesByType('navigation')[0]这里面获取到。
  5. 如果你想衡量网络请求响应时间的指标:responseStart - fetchStart,代表从发起网络请求(fetchStart)到服务器开始响应(responseStart)的时间间隔。
  6. 如果你想衡量页面加载速度的指标:domInteractive - fetchStart,代表从发起网络请求(fetchStart)到DOM解析完成(domInteractive)的时间间隔。
  7. domComplete - fetchStart 这个差值基本上囊括了最核心的部分。包括了从开始获取页面资源到 DOM 解析完成的整个过程,其中包括了网络请求、资源加载、解析 HTML、构建 DOM 树等操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/11322.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法训练营第二天| 977

977. 有序数组的平方y 思路,原数组是有序的,但是因为负数平方后可能变无序了,因此利用双指针遍历原数组,比较 nums[left]*nums[left]和nums[right]*nums[right]谁更大,然后对新数组赋值 class Solution {public int…

MFC第二十四天 使用GDI对象画笔和画刷来开发控件(分页控件选择态的算法分析、使用CToolTipCtrl开发动静态提示)

文章目录 GDI对象画笔和画刷来开发控件梯形边框的按钮控件CMainDlg.hCMainDlg.cppCLadderCtrl.hCLadderCtrl.cpp 矩形边框的三态按钮控件 CToolTipCtrl开发动静态提示CMainDlg.hCMainDlg.cppCLadderCtrl.hCLadderCtrl.cpp: 实现文件 矩形边框的三态按钮控件 CToolTipCtrl开发动…

欢乐暑假,华为儿童手表5系列为孩子位置安全保驾护航!

暑假带娃,就像爸妈的练兵场。幸好有 5 系列,离线定位、位置提醒、行为记录等安全守护功能面面俱到、样样精通,陪伴孩子度过悠长假期,也让爸妈长辈更安心更省力~ 暑期到了,小朋友们都想出去玩,但…

修改密码和再次确认密码的js和element-ui的使用

<template><div><!-- plan的插槽 --><plan title"修改密码"><!-- 插槽的名字 --><span slot"header">修改密码</span><el-form:model"ruleForm2"status-icon:rules"rules2"ref"rul…

【数据结构】实验七:字符串

实验七 字符串实验报告 一、实验目的与要求 1&#xff09;巩固对串的理解&#xff1b; 2&#xff09;掌握串的基本操作实现&#xff1b; 3&#xff09;掌握 BF 和 KMP 算法思想。 二、实验内容 1. 给定一个字符串ababcabcdabcde和一个子串abcd,查找字串是否在主串中出现。…

【数据结构】实验一:绪论

实验一 绪论 一、实验目的与要求 1&#xff09;熟悉C/C语言&#xff08;或其他编程语言&#xff09;的集成开发环境&#xff1b; 2&#xff09;通过本实验加深对算法时间复杂度的理解&#xff1b; 3&#xff09;结合具体的问题分析算法时间复杂度。 二、实验内容 设计程…

深入学习 redis - Stream、Geospatial、HyperLogLog、Bitmap、Bitfields 类型扩展

目录 前言 Stream geospatial HyperLogLog Bitmaps Bitfields 前言 redis 中最关键的五个数据类型 String、List、Hash、Set、Zset 应用最广泛&#xff0c;同时 redis 也推出了额外的 5 个数据类型&#xff0c;他们分别是针对特殊场景才进行的应用的. Ps&#xff1a;这几种…

odoo16-domain

odoo16-domain 参考:https://blog.csdn.net/u013250491/article/details/86699928 domain的使用注意以下几点: 是在py文件中使用还是在xml中使用,py文件是在后端使用可以利用orm, 而xml是在前端渲染,使用的是js,没有办法使用orm如果在xml中使用,domain的格式建议为[[]], 二维…

Paragon NTFS2023最新版Mac读写NTFS磁盘工具

Paragon NTFS for Mac是Mac平台上一款非常优秀的读写工具&#xff0c;可以在Mac OS X中完全读写、修改、访问NTFS硬盘、U盘等外接设备的文件。这款软件最大的亮点简书可以让我们读写 NTFS 分区&#xff0c;因为在Mac OS X 系统上&#xff0c;默认状态下我们只能读取NTFS 分区&a…

速成版-带您一天学完python自动化测试(selenium)

Selenium是一套web网站的程序自动化操作解决方案。我们通过编写自动化程序&#xff0c;使得自动完成浏览器界面的相关操作&#xff0c;除了能够自动化的完成相关操作&#xff0c;还能从web页面获取相关信息&#xff0c;然后通过程序进行分析处理&#xff0c;本质上就是提升从网…

25.5 matlab里面的10中优化方法介绍——牛顿法(matlab程序)

1.简述 1 牛顿法简介 牛顿迭代法&#xff08;Newton’s method&#xff09;又称为牛顿-拉夫逊&#xff08;拉弗森&#xff09;方法&#xff08;Newton-Raphson method&#xff09;&#xff0c;它是牛顿在17世纪提出的一种在实数域和复数域上近似求解方程的方法。 多数方程不存…

【spring】spring bean的生命周期

spring bean的生命周期 文章目录 spring bean的生命周期简介一、bean的创建阶段二、bean的初始化阶段三、bean的销毁阶段四、spring bean的生命周期总述 简介 本文测试并且介绍了spring中bean的生命周期&#xff0c;如果只想知道结果可以跳到最后一部分直接查看。 一、bean的…

图像滤波器

图像噪声 • 图像噪声是图像在获取或是传输过程中受到随机信号干扰&#xff0c;妨碍人们对图像理解及分析处理 的信号。 • 图像噪声的产生来自图像获取中的环境条件和传感元器件自身的质量&#xff0c;图像在传输过程中产 生图像噪声的主要因素是所用的传输信道受到了噪声…

【技术架构】技术架构的演进

文章目录 前言1.名词解释(常见概念)1.1 应用&#xff08;Application&#xff09; / 系统&#xff08;System&#xff09;1.2 模块&#xff08;Module&#xff09; / 组件&#xff08;Component&#xff09;1.3 分布式&#xff08;Distributed&#xff09;1.4 集群&#xff08;…

机器学习 day30(正则化参数λ对模型的影响)

λ对Jcv和Jtrain的影响 假设该模型为四阶多项式当λ很大时&#xff0c;在最小化J的过程中&#xff0c;w会很小且接近0&#xff0c;此时模型f(x)近似于一个常数&#xff0c;所以此时模型欠拟合&#xff0c;Jtrain和Jcv都很大当λ很小时&#xff0c;表示模型几乎没有正则化&…

5.2.tensorRT基础(2)-使用onnx解析器来读取onnx文件(源码编译)

目录 前言1. ONNX解析器2. libnvonnxparser.so3. 源代码编译4. 补充知识总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 t…

Rocky Linux 8.4在Tesla P100服务器里的部署及显卡cudnn安装-极度精简

安装Rocky linux教程 https://developer.aliyun.com/article/1074889 注意事项 Tesla P100服务器&#xff0c;按Delete进入bios,设置Daul模式&#xff0c;第一选项选UEFI hard disk(用驱动盘选这个)&#xff0c;usb的就选UEFI usb 安装rocky linux时&#xff0c;这两项默认&…

css中flex后文本溢出的问题

原因&#xff1a; 为了给flex item提供一个合理的默认最小尺寸&#xff0c;flex将flex item的min-width 和 min-height属性设置为了auto flex item的默认设置为&#xff1a; min-width&#xff1a; auto 水平flex布局 min-height&#xff1a;auto 垂直flex布局 解决办法&…

【ICCV2023】Scale-Aware Modulation Meet Transformer

Scale-Aware Modulation Meet Transformer, ICCV2023 论文&#xff1a;https://arxiv.org/abs/2307.08579 代码&#xff1a;https://github.com/AFeng-x/SMT 解读&#xff1a;ICCV2023 &#xff5c; 当尺度感知调制遇上Transformer&#xff0c;会碰撞出怎样的火花&#xff1…

【Nodejs】Node.js简介

1.前言 Node 的重要性已经不言而喻&#xff0c;很多互联网公司都已经有大量的高性能系统运行在 Node 之上。Node 凭借其单线程、异步等举措实现了极高的性能基准。此外&#xff0c;目前最为流行的 Web 开发模式是前后端分离的形式&#xff0c;即前端开发者与后端开发者在自己喜…