Angular由一个bug说起之十二:网页页面持续占用CPU过高

news2025/2/25 7:37:02

随着网络日益发达,网页的内容也更加丰富,形式也更加多样化。而随之而来的性能问题也不容小觑。这篇文章我会根据我在实践中遇到的一个问题来总结,我在面对性能问题的一些解决步骤,希望能对大家有所启发。

查找问题原因

我接触的项目中有数据可视化的功能,在编辑可视化组件时页面会有明显卡顿,并且在页面加载完毕后也能感受到操作不流畅。

这种情况下我们一般使用排除法来查找出现问题的原因。首先查看 Devtool 是否有报错的情况,其次检查网络连接状况。

我使用的浏览器是 Chrome,如果有报错就会在 Console 里面观察到。网络状况我一方面使用 Ping 来测试服务器连接是否异常,另一方面选择下载文件(我下载的是 node.js)来测试网络速度,以此来判断是否网络问题造成的卡顿。

在我完成了对上面两点的检测后我就排除了由代码或网络引发这个问题的可能性。那么接下来很容易就让人想到是否性能出现了不合理的消耗。

关于性能,我们都知道网页所消耗的计算机资源第一是内存,第二是CPU。我用的系统是 Windows,而这两个指标可以在 Task Manager 中查看。

上图是相对正常时各指标的占用率或速率。当时我所观察到的情况是,内存保持在 50%-60% 的占用率,而 CPU 的占用率已经超过 95%,甚至到达 100%。那么原因就一目了然了,一定是出现了大量的需要计算的情况才导致页面卡顿。再考虑到页面在加载完成后依然保持极高的 CPU 占用率。

由此推断,最有可能的情况是:当前页面存在一个或多个不间断的监听事件,这些监听事件随着页面被加载而运行,导致 CPU 资源被持续占用。

解决过程

既然已经得出了一个合理的假设,那么就可以查看代码中是否存在持续调用的监听事件了。实际上,我在项目中发现了多处监听。

window.resize,mousemove,scroll,还包括钩子函数。这些都是在满足条件时会持续调用的方法,那么怎么确定是哪一个出现了问题呢?

我第一次判断是 window.resize 的问题,因为我在 window.resize 的回调函数中看到了一些 DOM 操作。这里其实应该做进一步的验证,但是我想当然的下了结论。我将 window.resize 删掉并测试结果,发现 CPU 占用率确实降低了,但是闲置时依然高达 60%。正常情况下这个数值应当不超过 10%。我意识到我的结论下的太早了,我需要更多的信息来找出真正的原因。

这时我想到可以借助工具,比如 Devtools。

使用 Chrome 的 Performance 来对页面的性能进行分析,结果如下:

这是从打开可视化编辑页面直到页面完全加载完毕的性能分析报告。从节选出的这部分可以看到一个叫 Animation frame 的 function 在持续的执行,问题肯定就出在它身上。

再次对代码进行查看后我将目标锁定在了 window.requestAnimationFrame() 上。

requestAnimationFrame

先来简单介绍 requestAnimationFrame:

它是一个浏览器的宏任务。 requestAnimationFrame 的用法与 setTimeout、setInterval 很相似,只是不需要设置时间间隔而已。requestAnimationFrame 使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。它返回一个整数,表示定时器的编号,这个值可以传递给 cancelAnimationFrame 用于取消这个函数的执行。

大多数电脑显示器的刷新频率是 60Hz,大概相当于每秒钟重绘 60 次。大多数浏览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。因此最平滑动画的最佳循环间隔是1000ms/60,约等于 16.6ms。

在之前,为了实现动画,常常使用 setTimeout() 或 setInterval() 方法来定时更新动画帧。然而,这种方法并不理想,因为它们受限于定时器的精度和浏览器在不同设备上的性能差异。它们的内在运行机制决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器 UI 线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行。

requestAnimationFrame 的出现解决了这个问题。它使用浏览器的刷新率作为参考,确保动画帧的更新在每一帧之间的间隔是最佳的,从而实现更加流畅和自然的动画效果。

requestAnimationFrame 引发的问题

如上所述,requestAnimationFrame 是一个类似于 setTimeout 或 setInterval 的方法。它虽然对性能更加友好,但是使用不当也会出现我们现在看到的问题。原因主要集中在 requestAnimationFrame 的回调函数。

requestAnimationFrame 作为一种高频发的事件,假如在回调函数中频繁的进行 DOM 操作,并且没有及时停止事件的触发,就会对性能造成巨大的影响。

项目中用到 requestAnimationFrame 的地方有两个,其中一个是 window.resize 另一个是 scroll。这也就是为什么我第一次尝试删掉 window.resize 的时候 CPU 占用率只下降到 60% 的原因。

接下来就是动手解决这个问题了。我发现 window.resize 中的 DOM 操作是为了给一个变量赋值,而这个变量在 scroll 的回调中被用到,而其它的代码已经失去了实际的作用。所以将两处代码整合,放弃使用 requestAnimationFrame,直接监听 scroll event。那么 requestAnimationFrame 也就可以删掉了。

做完这一切之后,再检测 Chrome 的 Performance 结果如下:

可以看到资源的消耗主要集中在加载页面的期间,而在闲置阶段不会过多的占用性能。

解决问题的方法不止一个,我之所以能直接删掉 requestAnimationFrame,而不担心破坏原有功能是因为项目中的这段代码已经没有实际作用了,属于历史遗留问题。

而如果我们要保证原有功能的正常运行,也有两个方案可以选择。

  1. 替代:requestAnimationFrame 往往被用于动画渲染方面的功能。尝试用 CSS 动画来代替它
  2. 优化:不在 requestAnimationFrame 的回调中做大量运算,在满足条件后及时的停止 requestAnimationFrame

总结

性能问题在实际项目中已经屡见不鲜,我们想改善项目的体验或者降低资源的消耗就必须要面对它。相对于常见的 bug 或者新增功能来说,解决性能问题更加的棘手。另外,在没有直接证据的情况下,不应该凭直觉来判断原因,而是多利用各种工具来解决问题。

为了方便入手解决以后可能遇到的类似问题,我将过程总结如下:

以上是我对此次资源占用问题的全部总结,谢谢。

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

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

相关文章

WordPress全能CDN插件_自动刷新预热_缓存优化|国内国外集成CDN配置

WordPress全网独家原创CDN插件 自动刷新预热 缓存优化 国内国外集成CDN配置 支持白山云 cdnfly Cloudflare PS:目前国内集成了CDNfly,白山云国外集成了Cloudflare,更新手动刷新,全站刷新,优化提交线程,根据网友建议适配阿里云,le…

唇形同步视频生成工具:Wav2Lip

一、模型介绍 今天介绍一个唇形同步的工具-Wav2Lip;Wav2Lip是一种用于生成唇形同步(lip-sync)视频的深度学习算法,它能够根据输入的音频流自动为给定的人脸视频添加准确的口型动作。 (Paper) Wav2Lip模型…

【汽车】-- 燃油发动机3缸和4缸

3缸和4缸燃油发动机是小轿车常见的发动机配置。以下从结构特点、性能、经济性等方面对两者进行对比,并分析优缺点及使用注意事项: 1. 结构与运行原理 3缸发动机 特点:少一个气缸,内部零部件更少,整体结构更紧凑。优点…

[NeurlPS 2022] STaR 开源代码实现解读

STaR 方法代码开源,这里给出一个中文代码解读地址:repo入口点:iteration_train.py;关键代码:device_train.py, device_inference.py, and create_finetune_tfrecords.py;基于 JAX、RAY,在 Googl…

欢迪迈手机商城设计与实现

文末获取源码和万字论文,制作不易,感谢点赞支持。 题目:欢迪迈手机商城设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管…

【鸿蒙实战开发】数据的下拉刷新与上拉加载

本章介绍 本章主要介绍 ArkUI 开发中最常用的场景下拉刷新, 上拉加载,在本章中介绍的内容在实际开发过程当中会高频的使用,所以同学们要牢记本章的内容。下面就让我们开始今天的讲解吧! List 组件 在 ArkUI 中List容器组件也可以实现数据滚动的效果&a…

UnityShaderLab 实现程序化形状(一)

1.实现一个长宽可变的矩形: 代码: fixed4 frag (v2f i) : SV_Target{return saturate(length(saturate(abs(i.uv - 0.5)-0.13)))/0.03;} 2.实现一个半径可变的圆形: 代码: fixed4 frag (v2f i) : SV_Target{return (distance(a…

高阶数据结构--B树B+树实现原理B树模拟实现--Java

目录 一、B-树概念 二、B-树插入分析 1.用序列{53, 139, 75, 49, 145, 36, 101}构建B树的过程如下: 2.插入过程总结 三、B树插入实现 四、B树 1.B树概念 2.B树的特性 五、B树应用 1.索引 2.Mysql索引 3.InnoDB 一、B-树概念 1970 年, R.Bayer 和…

网络安全——防火墙

基本概念 防火墙是一个系统,通过过滤传输数据达到防止未经授权的网络传输侵入私有网络,阻止不必要流量的同时允许必要流量进入。防火墙旨在私有和共有网络间建立一道安全屏障,因为网上总有黑客和恶意攻击入侵私有网络来破坏,防火…

基于Qwen2-VL模型针对LaTeX OCR任务进行微调训练 - 多图推理

基于Qwen2-VL模型针对LaTeX OCR任务进行微调训练 - 多图推理 flyfish 基于Qwen2-VL模型针对LaTeX_OCR任务进行微调训练_-_LoRA配置如何写 基于Qwen2-VL模型针对LaTeX_OCR任务进行微调训练_-_单图推理 基于Qwen2-VL模型针对LaTeX_OCR任务进行微调训练_-_原模型_单图推理 基于Q…

Ant Design Pro实战--day01

下载nvm https://nvm.uihtm.com/nvm-1.1.12-setup.zip 下载node.js 16.16.0 //非此版本会报错 nvm install 16.16.0 安装Ant Design pro //安装脚手架 npm i ant-design/pro-cli -g //下载项目 pro create myapp //选择版本 simple 安装依赖 npm install 启动umi yarn add u…

一、为什么要学习麒麟?

麒麟认证:开启职业晋升之门 当前,就业难已经成为一个普遍的社会问题。许多大学生毕业后面临着找工作的困境,他们往往发现自己很难找到满意的职位。即使有幸找到了工作,也经常需要应对工作压力大、薪资低等问题。除此之外&#xff…

python如何减小维度

ravel():将多维数组拉平(一维)。 flatten():将多维数组拉平,并拷贝一份。 squeeze():除去多维数组中,维数为1的维度&…

未来已来:人工智能如何重塑我们的生活与工作

引言 未来的生活和工作场景正从想象走向现实。想象一下,一个清晨,语音助手已经为你安排好一天的任务,自动驾驶汽车准时送你上班,智能冰箱提醒你需要补充的食材。曾经只存在于科幻小说中的场景,如今正在我们的身边实现。…

Adminer源码编译 精简语言中英文和基本使用方法

Adminer是一个小而强悍的基于web的数据库管理工具, 官方默认支持几十种语言,但是对于中国的用户而言只需要有中文和英文就够了,其他语言基本无用。这就需要我们下载Adminer源码自己编译 Adminer.php , 如下图所示 adminer 中英文语言精简版本…

字符编码讲解(C#)

在学习和编码的过程中,极容易遇到如下概念,他们有些是字符编码,有些是涉及的相关概念,接下来我将围绕下面的熟悉又陌生的概念做详细解释,并且梳理其之间的关系 UTF8, Unicode ,ASCII&#xff0…

Mac备忘录表格中换行(`Option` + `Return`(回车键))

在Mac的ARM架构设备上,如果你使用的是Apple的原生“备忘录”应用来创建表格,换行操作可以通过以下步骤来实现: 在单元格中换行: 双击你想要编辑的单元格你可以输入文本,按Option(⌥) Enter来插…

Windows中将springboot项目运行到docker的容器中

0,先打包好项目,再启动docker 1,在Java项目根目录下创建一个名为Dockerfile的文件(没有扩展名),并添加以下内容。 # 使用OpenJDK的基础镜像 FROM openjdk:8-jdk-alpine# 设置工作目录 WORKDIR /app# 将项…

HBU深度学习实验14.5-循环神经网络(1.5)

梯度爆炸实验 造成简单循环网络较难建模长程依赖问题的原因有两个:梯度爆炸和梯度消失。一般来讲,循环网络的梯度爆炸问题比较容易解决,一般通过权重衰减或梯度截断可以较好地来避免;对于梯度消失问题,更加有效的方式…

ZED相机应用

下载SDK wget https://stereolabs.sfo2.cdn.digitaloceanspaces.com/zedsdk/3.6/ZED_SDK_Ubuntu18_cuda11.5_v3.6.5.run 安装 ./ZED_SDK_Ubuntu18_cuda11.5_v3.6.5.run skip_python 测试 cd /usr/local/zed/tools ls ZED_Calibration ZED_Depth_Viewer ZED_Diagnostic ZED_E…