前端vite+vue3——可视化页面性能耗时指标(fmp、fp)

文章目录

    • ⭐前言
      • 💖vue3系列文章
    • ⭐可视化fmp、fp指标
      • 💖 MutationObserver 计算 dom的变化
      • 💖 使用条形图展示 fmp、fp时间
    • ⭐项目代码
    • ⭐结束

yma16-logo

⭐前言

大家好,我是yma16,本文分享关于 前端vite+vue3——可视化页面性能耗时(fmp、fp)。
performance

fmp的定义

FMP(First Meaningful Paint)是一种衡量网页加载性能的指标。它表示在加载过程中,浏览器首次渲染出有意义的内容所花费的时间。有意义的内容指的是用户可以看到和交互的元素,如文本、图片、按钮等。

首次渲染的定义可以根据具体的要求和场景而有所不同。通常情况下,首次渲染是指在页面加载过程中,浏览器首次绘制出用户能够理解和识别的内容,而不是空白页面或加载指示符。

FMP的计算方法可以根据不同的标准和工具而有所差异,但通常会考虑页面上可见的内容和用户可交互的元素。在计算FMP时,一般会排除一些延迟加载的元素,如懒加载的图片或动态加载的内容,以确保测量的是真正有意义的渲染时间。

fp的定义

FP(First Paint)是指浏览器首次将像素渲染到屏幕上的时间点

count

💖vue3系列文章

vue3 + fastapi 实现选择目录所有文件自定义上传到服务器
前端vue2、vue3去掉url路由“ # ”号——nginx配置
csdn新星计划vue3+ts+antd赛道——利用inscode搭建vue3(ts)+antd前端模板
认识vite_vue3 初始化项目到打包
python_selenuim获取csdn新星赛道选手所在城市用echarts地图显示
让大模型分析csdn文章质量 —— 提取csdn博客评论在文心一言分析评论区内容
前端vue3——html2canvas给网站截图生成宣传海报
vue3+echarts可视化——记录我的2023编程之旅
前端vite+vue3——自动化配置路由布局

⭐可视化fmp、fp指标

由于vue是SPA(single-page application)单页面项目,会导致首次加载时间长:SPA需要加载整个应用的代码和资源,首次加载时间可能会比传统的多页面应用长。

以下是我个人计算fmp的逻辑

  • fmp:监听 vue挂载的节点(dom的id为root)首次变化时间
  • fp: 监听 beforeMounted的时间为白屏结束时间

计算的单位使用performance.now

performance.now()是一个JavaScript方法,用于获取当前时间戳,精确到毫秒级。它返回一个DOMHighResTimeStamp对象,表示从性能测量器启动到调用performance.now()的时间间隔。这个方法通常用于性能测量和性能优化,可以用于计算代码执行时间、动画帧率、网络请求延迟等。

💖 MutationObserver 计算 dom的变化

MutationObserver 接口提供了监视对 DOM 树所做更改的能力

使用示例:

// 选择需要观察变动的节点
const targetNode = document.getElementById("some-id");// 观察器的配置(需要观察什么变动)
const config = { attributes: true, childList: true, subtree: true };// 当观察到变动时执行的回调函数
const callback = function (mutationsList, observer) {// Use traditional 'for loops' for IE 11for (let mutation of mutationsList) {if (mutation.type === "childList") {console.log("A child node has been added or removed.");} else if (mutation.type === "attributes") {console.log("The " + mutation.attributeName + " attribute was modified.");}}
};// 创建一个观察器实例并传入回调函数
const observer = new MutationObserver(callback);// 以上述配置开始观察目标节点
observer.observe(targetNode, config);// 之后,可停止观察
observer.disconnect();

在vue的入口页面app.vue编写监听rootDom变化的逻辑
mutationAction 函数如下(将节点的高度大于0作为结束监听的条件即fmp的结束时间)

// 监听 dom变化
mutationAction(listenDom, callbackAction) {// 观察器的配置(需要观察什么变动)const config = { attributes: true, childList: true, subtree: true };// 当观察到变动时执行的回调函数const callback = function (mutationsList, observer) {// 渲染高度const renderHeight = listenDom.offsetHeightif (parseInt(renderHeight)) {// 第一次监听dom 存在高度则判定已经渲染完root节点callbackAction()// 停止观察observer.disconnect();}};// 创建一个观察器实例并传入回调函数const observer = new MutationObserver(callback);// 以上述配置开始观察目标节点observer.observe(listenDom, config);
}

在App.vue的声明周期onBerforeMount运行

<script setup>
import { ref, onBeforeMount } from "vue";
// 查找次数,用于统计最大查找次数避免奔溃
const findAppCount = ref(0)// 监听 dom变化
mutationAction(listenDom, callbackAction) {// 观察器的配置(需要观察什么变动)const config = { attributes: true, childList: true, subtree: true };// 当观察到变动时执行的回调函数const callback = function (mutationsList, observer) {// 渲染高度const renderHeight = listenDom.offsetHeightif (parseInt(renderHeight)) {// 第一次监听dom 存在高度则判定已经渲染完root节点callbackAction()// 停止观察observer.disconnect();}};// 创建一个观察器实例并传入回调函数const observer = new MutationObserver(callback);// 以上述配置开始观察目标节点observer.observe(listenDom, config);
}const findAppDom = () => {const appDom = document.getElementById('app')findAppCount.value += 1if (appDom) {mutationAction(appDom, () => {const fmp=performance.now()})}else if (findAppCount <= 1000) {findAppDom()}
}
onBeforeMount(() => {// 白屏时间const fp = performance.now()findAppDom();
})
</script>

💖 使用条形图展示 fmp、fp时间

使用条形图对性能指标耗时进行可视化
line-bar
条形图展示数据的vue界面编写

<script lang="js" setup>
import { reactive, onMounted } from 'vue';
import * as echarts from 'echarts';import { useStore } from "vuex";const store = useStore();
const state = reactive({leftTitle: '原生的performance',leftDomId: 'visual-performance-id',rightTitle: '性能指标可视化',rightDomId: 'visual-performance-id-right',chartTitle: '性能指标',echartInstance: null,})const initLeftChart = () => {// 基于准备好的dom,初始化echarts实例const domInstance = document.getElementById(state.leftDomId)if (domInstance) {domInstance.removeAttribute('_echarts_instance_')}else {return}console.log(performance)console.log(Object.keys(performance.timing))const label = []const data = []for (let key in performance.timing) {if (key != 'toJSON') {label.push(key)data.push(performance.timing[key])}}const myChart = echarts.init(domInstance);const option = {title: {text: 'performance'},tooltip: {trigger: 'axis',axisPointer: {type: 'shadow'}},legend: {},grid: {left: '3%',right: '4%',bottom: '3%',containLabel: true},xAxis: {type: 'value',boundaryGap: [0, 0.01]},yAxis: {type: 'category',data: label},series: [{name: 'performance',type: 'bar',data: data}]};console.log('option', option)// 使用刚指定的配置项和数据显示图表。myChart.setOption(option, true);// 监听state.echartInstance = myChart;myChart.on('click', function (params) {console.log('params', params)});window.onresize = myChart.resize;
}const initRightChart = () => {// 基于准备好的dom,初始化echarts实例const domInstance = document.getElementById(state.rightDomId)if (domInstance) {domInstance.removeAttribute('_echarts_instance_')}else {return}const performanceConfig = store.getters["common/performanceConfig"]console.log('performanceConfig________________', performanceConfig)const label = []const data = []Object.keys(performanceConfig).forEach(key => {data.push(performanceConfig[key])label.push(key)})const myChart = echarts.init(domInstance);const option = {title: {text: '自定义计算fmp'},tooltip: {trigger: 'axis',axisPointer: {type: 'shadow'}},legend: {},grid: {left: '3%',right: '4%',bottom: '3%',containLabel: true},xAxis: {type: 'value',boundaryGap: [0, 0.01]},yAxis: {type: 'category',data: label},series: [{name: 'fmp计算',type: 'bar',data: data}]};console.log('option', option)// 使用刚指定的配置项和数据显示图表。myChart.setOption(option, true);// 监听state.echartInstance = myChart;myChart.on('click', function (params) {console.log('params', params)});window.onresize = myChart.resize;
}onMounted(() => {initLeftChart()initRightChart()
})
</script>
<template><div><div style="display:flex;"><a-card :title="state.leftTitle" style="width: 600px"><div :id="state.leftDomId" style="width: 500px;height:600px;"></div></a-card><a-card :title="state.rightTitle" style="width: 600px;margin-left:20px"><div :id="state.rightDomId" style="width: 500px;height:600px;"></div><div></div></a-card><a-card style="margin-left:20px" title="定义"><div><div>fetchStart:浏览器发起资源请求时,有缓存时,则返回读取缓存的开始时间。<br>domainLookupStart:查询 DNS 的开始时间。<br>domainLookupEnd:查询 DNS 的结束时间。<br>connectStart:浏览器开始与服务器连接时的时间。<br>secureConnectionStart:如果页面使用 HTTPS,它的值是安全连接握手之前的时刻。<br>connectEnd:当浏览器端完成与服务器端建立连接的时刻。<br>responseStart:指客户端收到从服务器端(或缓存、本地资源)响应回的第一个字节的数据的时刻。<br>responseEnd:指客户端收到从服务器端(或缓存、本地资源)响应回的最后一个字节的数据的时刻。<br></div></div></a-card></div></div>
</template>

效果:
visual-fmp

⭐项目代码

前端项目inscode如下:

⭐结束

本文分享到这结束,如有错误或者不足之处欢迎指出!
earth

👍 点赞,是我创作的动力!
⭐️ 收藏,是我努力的方向!
✏️ 评论,是我进步的财富!
💖 最后,感谢你的阅读!

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

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

相关文章

图像处理与图像分析—图像的读入(C语言)

学习将会依据教材图像处理与图像分析基础&#xff08;C/C&#xff09;版内容展开 什么是数字图像处理 一副图像可以定义为一个二维函数 f(x&#xff0c;y) &#xff0c;其中 x 和 y 是空间&#xff08;平面&#xff09;坐标&#xff0c;任意一对空间坐标 (x,y) 处的幅度值 &am…

微信私信短剧机器人源码

本源码仅提供参考&#xff0c;有能力的继续开发 接口为api调用 云端同步 https://ys.110t.cn/api/ajax.php?actyingshilist 影视搜索 https://ys.110t.cn/api/ajax.php?actsearch&name剧名 每日更新 https://ys.110t.cn/api/ajax.php?actDaily 反馈接口 https://ys.11…

R语言复现:中国Charls数据库一篇现况调查论文的缺失数据填补方法

编者 在临床研究中&#xff0c;数据缺失是不可避免的&#xff0c;甚至没有缺失&#xff0c;数据的真实性都会受到质疑。 那我们该如何应对缺失的数据&#xff1f;放着不管&#xff1f;还是重新开始?不妨试着对缺失值进行填补&#xff0c;简单又高效。毕竟对于统计师来说&#…

NUC980开发板CAN开发笔记

一、内核开启CAN CAN 设置 NUC980 系列带有2个CAN(Controller Area Network), 可以分别独立设置。 请按以下的说明来使能CAN功能. 每个CAN可以单独的开关. CAN0有多组管脚可以选择, 需要一并设置。 使用者也可以设置CAN的唤醒功能。步骤如下&#xff1a; 进入 NUC980-linux-4.…

使用Tokeniser估算GPT和LLM服务的查询成本

将LLM集成到项目所花费的成本主要是我们通过API获取LLM返回结果的成本&#xff0c;而这些成本通常是根据处理的令牌数量计算的。我们如何预估我们的令牌数量呢&#xff1f;Tokeniser包可以有效地计算文本输入中的令牌来估算这些成本。本文将介绍如何使用Tokeniser有效地预测和管…

异步编程实战:使用C#实现FTP文件下载及超时控制

博客标题: 异步编程实战&#xff1a;使用C#实现FTP文件下载及超时控制 如果你的函数不是async&#xff0c;你仍然可以实现相同的超时功能&#xff0c;但你将不得不依赖更多的同步代码或使用.Result或.GetAwaiter().GetResult()来阻塞等待任务完成&#xff0c;这可能导致死锁的风…

verilog中的函数和for循环

在Verilog中&#xff0c;clogb2 的英文全称是 “ceiling&#xff08;天花板&#xff09; log base 2”&#xff0c;表示对输入参数取对数&#xff08;以2为底&#xff09;&#xff0c;并向上取整到最接近的整数值。这个函数通常用于计算内存地址宽度或状态数所需的位数12。 fun…

STM32---通用定时器(二)相关实验

写在前面&#xff1a;前面我们学习了基本定时器、通用定时器的相关理论部分&#xff0c;了解到通用定时器的结构框图&#xff0c;总共包含六大模块&#xff1a;时钟源、控制器、时基单元、输入捕获、公共部分以及输出捕获。对相关模块的使用也做详细的讲解。本节我们主要是对上…

Day33-计算机基础3

Day33-计算机基础3 1.根据TCP/IP进行Linux内核参数优化1.1 例1&#xff1a;调整访问服务端的【客户端】的动态端口范围 &#xff0c;LVS&#xff08;10-50万并发&#xff09;&#xff0c;NGINX负载&#xff0c;SQUID缓存服务,1.2 企业案例&#xff1a;DOS攻击的案例&#xff1a…

[备赛笔记]——5G大唐杯(5G考试等级考考试基础试题)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;Vir2021GKBS &#x1f43c;本文由…

redis缓存满了的话会发生什么?

线上问题 未及时加监控&#xff0c;导致线上redis被逐出&#xff0c;业务有损 示例&#xff1a; 一个key临时存储在redis等缓存中&#xff0c;如果该key在一段时间内有很大作用 比如一次业务请求&#xff0c;上游服务写入一个value&#xff0c;时长1小时&#xff0c;下游服务…

Matlab|考虑源荷两侧不确定性的含风电电力系统低碳调度

目录 1 主要内容 目标函数&#xff1a; 约束条件&#xff1a; 程序亮点总结&#xff1a; 2 代码问题与程序测试 设备出力运行结果&#xff1a; 3 下载链接 1 主要内容 本程序是对《考虑源荷两侧不确定性的含风电电力系统低碳调度》的方法复现&#xff0c;主要实现了基…

【QT+QGIS跨平台编译】之七十六:【QGIS_Native+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、QGIS_Native介绍二、QGIS下载三、文件分析四、pro文件五、编译实践一、QGIS_Native介绍 QGIS_Native模块是QGIS软件的核心部分,提供了许多基本功能和核心组件,主要用于处理与底层操作系统的关系。 二、QGIS下载 QGIS网址: QGIS Source Download 三、文件分析…

Django学习笔记

Django学习笔记 一、Django整体流程跑通 1.1安装 pip install django //安装 import django //在python环境中导入django django.get_version() //获取版本号&#xff0c;如果能获取到&#xff0c;说明安装成功Django目录结构 Python310-Scripts\django-admi…

前端框架的发展历程

文章目录 前言 一、静态页面时代 二、JavaScript的兴起 三、jQuery的出现 四、前端框架的崛起 1.AngularJS 2.React 3.Vue.js 五、面向组件化的发展趋势 总结 前言 前端框架的发展史就是一个不断进化的过程&#xff0c;它的发展和进化一定程度…

力扣刷题Days14第二题--80删除数组中重复元素||(js)

目录 1&#xff0c;题目-中等 2&#xff0c;代码 双指针 3&#xff0c;学习与总结 思路学习与整理 1&#xff0c;题目-中等 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组…

区块链和人工智能的关系以及经典案例

目录 1.区块链与人工智能的关系 2.应用案例&#xff1a;基于区块链的医疗数据共享平台 2.1背景 2.2方案 2.3优势 2.4挑战 区块链技术和人工智能&#xff08;AI&#xff09;是两种不同的技术&#xff0c;但它们之间存在着互补关系。区块链技术提供了一种安全、透明、去中心…

Android Studio下载gradle超时问题解决

方法一 1. 配置根目录的setting.gradle.kts文件 pluginManagement {repositories {maven { urluri ("https://www.jitpack.io")}maven { urluri ("https://maven.aliyun.com/repository/releases")}maven { urluri ("https://maven.aliyun.com/repos…

Open-Sora:开源 Sora 复现方案,成本降低 46%

Colossal-AI 开源了完整的 Sora 复现架构方案 Open-Sora&#xff0c;声称可降低 46% 复现成本&#xff0c;并将模型训练输入序列长度扩充至 819K patches。 演示站点&#xff1a; https://ai.uaai.cn UAAI 官方论坛&#xff1a; www.jingyuai.com京娱AI Sora 算法复现方案 在 …

springboot256基于springboot+vue的游戏交易系统

游戏交易系统设计与实现 摘 要 在如今社会上&#xff0c;关于信息上面的处理&#xff0c;没有任何一个企业或者个人会忽视&#xff0c;如何让信息急速传递&#xff0c;并且归档储存查询&#xff0c;采用之前的纸张记录模式已经不符合当前使用要求了。所以&#xff0c;对游戏交…