昂贵的DOM操作:一次DOM导致的性能问题排查记录

公司来了一个前端实习生,踏实,勤快,很快得到老大的认可,分配给她一个需求,大概如下:构建一个公司产品的评论展示页面,页面可以滚动加载新的内容,同时如果已经加载的内容发生变化(比如:点赞数)也要跟新。

现象

开发完成之后,对接后端连调,由于开始连调的是测试环境,环境当中没有很多数据,所以没有发现问题,于是接入公司真实数据接口,发现确实很卡,尤其是滚动加载的时候,于是测试打回,对于实习生,尤其是妹子,大家开始帮忙看问题。

排查思路

确实遇到这样的问题,总是有一套完整的流程区排查,这里分享一下我个人的习惯思路:

1. 初步症状确认

  • 观察现象:页面是否出现明显卡顿、滚动不流畅、更新延迟

  • 用户反馈:收集用户关于特定页面/操作卡顿的报告

  • 性能指标:监控FPS(帧率)、CPU占用率、内存使用情况

2. 浏览器工具分析

这个是我最常用的,也希望能和大家讨论

Chrome DevTools 使用步骤:

  1. Performance面板录制

    • 重现问题场景同时录制性能时间线

    • 重点关注:

      • 长任务(Long Tasks,超过50ms的任务)

      • 频繁的Layout(重排)和Paint(重绘)

      • 高耗时的Function Call

  2. Memory面板检查

    • 拍摄堆快照,检查DOM节点数量是否异常增长

    • 检查是否有分离的DOM树(Dettached DOM tree)内存泄漏

  3. Rendering面板

    • 开启Paint flashing查看重绘区域

    • 开启Layout Shift Regions查看布局偏移

    • 开启FPS meter实时监控帧率

确定问题

自然,看了上面的参数,至少感觉我(接口端)没有大问题,然后发现重绘(paint)比较高,所以开始看前端代码

她的代码大概如下:

// 不好的实现方式 - 频繁操作DOM
function updateItems(items) {items.forEach(item => {const element = document.getElementById(`item-${item.id}`);if (element) {element.querySelector('.likes-count').textContent = item.likes;element.querySelector('.comments-count').textContent = item.comments;element.querySelector('.price').textContent = item.price;// 可能还有更多属性更新...}});
}
​
// 数据可能来自WebSocket或定期轮询
socket.on('item-updates', updateItems);

嗯,看到循环当中操作dom,那么肯定先怀疑dom消耗大问题,即使不是这个问题导致的,也得琢磨优化。

优化思路

确实也没有发现别的问题,那么就开始尝试减少dom操作,大概的思路就是检索dom跟新,想到两种:

1、使用文档片段,批量插入DOM,这个需要和产品沟通,滚动同时一条一条加载如果性能没有问题,那么用户体验肯定最好,但是卡了之后,用户体验只会更糟糕,所以滚动定长之后加载下面一页,然后批量生成文档片段,统一插入。

2、减少用户操作频率,这个自然不能要求用户慢慢的来,那么就寄出大招,节流/防抖

所以就做了以下调整,我贴出当时我思考构建的模拟代码:

// 更好的实现方式 - 批量更新
function updateItemsOptimized(items) {// 使用requestAnimationFrame减少重绘requestAnimationFrame(() => {// 创建文档片段const fragment = document.createDocumentFragment();const updates = new Map();// 先收集所有需要更新的元素items.forEach(item => {const element = document.getElementById(`item-${item.id}`);if (element) {updates.set(element, item);}});// 批量处理更新updates.forEach((item, element) => {const clone = element.cloneNode(true);clone.querySelector('.likes-count').textContent = item.likes;clone.querySelector('.comments-count').textContent = item.comments;clone.querySelector('.price').textContent = item.price;fragment.appendChild(clone);});// 一次性替换updates.forEach((_, element) => {element.parentNode.replaceChild(fragment.cloneNode(true), element);});});
}
​
// 加上防抖处理
const debouncedUpdate = _.debounce(updateItemsOptimized, 100);
socket.on('item-updates', debouncedUpdate);

当然,还有高级的思路,比如VUE和React虚拟DOM或者差异化更新、requestAnimationFrame在浏览器重绘周期内批量处理更新、CSS硬件加速:对频繁更新的元素使用transform/opacity等属性,这些也琢磨的用,但是考虑到太复杂(懒),而且优化后确实好很多,就不做了,不过效果已经有了。如果大家有其他思路欢迎一起聊聊。

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

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

相关文章

前端服务配置详解:从入门到实战

前端服务配置详解:从入门到实战 一、环境配置文件(.env) 1.1 基础结构 在项目根目录创建 .env 文件: # 开发环境 VUE_APP_API_BASE_URL http://localhost:3000/api VUE_APP_VERSION 1.0.0# 生产环境(.env.produc…

【学习笔记】计算机网络(七)—— 网络安全

第7章 网络安全 文章目录 第7章 网络安全7.1 网络安全问题概述7.1.1 计算机网络面临的安全性威胁7.1.2 安全的计算机网络7.1.3 数据加密模型 7.2 两类密码体制7.2.1 对称密钥密码体制7.2.2 公钥密码体制 7.3 鉴别7.3.1 报文鉴别7.3.2 实体鉴别 7.4 密钥分配7.4.1 对称密钥的分配…

我用Cursor + DeepSeek + Claude-3.7-Sonnet + DevBox,10分钟开发了一个系统

大家好,我是袁庭新。Cursor最近可谓是火的一塌糊涂,于是我深度体验了一波。我用的环境是Cursor Claude-3.7-Sonnet DevBox,整个过程我一行代码都没有写,10分钟帮我开发了一个系统,且前后端联调一把通过。惊出一身冷汗…

SpringBoot企业级开发之【用户模块-登录】

开发之前我们先看一下接口文档的要求: 开发思路: 开发实操: 因为我们之前开发注册的时候,就有了一些相关的操作,所以在这里我们只需要定义登录的controller即可: //用户登录PostMapping("/login"…

mysql 8.0.27-docker

安装 可以略过本步 https://dev.mysql.com/downloads/https://dev.mysql.com/downloads/ 镜像查询与安装 先查询: docker search mysql 明显会报错 Error response from daemon: Get "https://index.docker.io/v1/search?qmysql&n25": dial tcp…

Pgvector的安装

Pgvector的安装 向量化数据的存储,可以为 PostgreSQL 安装 vector 扩展来存储向量化数据 注意:在安装vector扩展之前,请先安装Postgres数据库 vector 扩展的步骤 1、下载vs_BuildTools 下载地址: https://visualstudio.microso…

Python高阶函数-sorted(深度解析从原理到实战)

一、sorted()函数概述 sorted()是Python内置的高阶函数,用于对可迭代对象进行排序操作。与列表的sort()方法不同,sorted()会返回一个新的已排序列表,而不改变原数据。 基本语法 sorted(iterable, *, keyNone, reverseFalse)二、核心参数详…

ArcGIS Pro/GeoScene Pro AI 助手 2.1

引言 面对ArcGIS Pro/GeoScene Pro复杂的操作界面和脚本开发需求,你是否还在为功能定位、代码调试和效率优化而烦恼?今天,推出自制的Pro AI助手2.0版本,七大核心功能将革新你的GIS工作方式!无论是界面操作指引、一键生…

如何将本地更改的README文件同步到自己的GitHub项目仓库

如何将本地更改的 README 文件同步到 GitHub 仓库 在你 git clone 下来的工程目录下: 先使用 robocopy YOUR\SOURCE\CODE\DIR YOUR\GIT\CLONE\DIR /E /XD .git /DCOPY:T 将你的更改Copy到你git下来的工程中(上面的命令会自动处理,例如只会C…

PostIn V1.0.8版本发布,IDEA 插件支持一键扫描上报,让接口定义不再繁琐

PostIn是一款国产开源免费的接口管理工具,包含项目管理、接口调试、接口文档设计、接口数据MOCK等模块,支持常见的HTTP协议、websocket协议等,支持免登陆本地接口调试,同时可以对项目进行灵活的成员权限、消息通知管理等。本周Pos…

UE5学习笔记 FPS游戏制作36 UI动画

文章目录 目的效果创建动画UI准备制作动画 播放动画目的效果创建动画UI准备制作动画 播放动画注册播放事件 目的效果 我们要创建一个提示动画,文字先渐显,然后向上移动,同时渐隐 创建动画 UI准备 创建一个UI控件,然后创建一个…

HTTP 响应头 Strict-Transport-Security 缺失漏洞

HTTP 响应头 Strict-Transport-Security 缺失漏洞 这个漏洞就是说明网站的HTTP响应头中没有设置Strict-Transport-Security,没有设置则可以通过将https自己手动改成htttp的方式进行访问。不安全 解决方法 1.nginx配置 nginx中增加如下配置: location / …

代理模式的优缺点是什么?

什么是代理模式? 代理模式(Proxy Pattern)是一种结构型设计模式,它通过创建代理对象来控制对原始对象的访问。 这种模式在前端开发中广泛应用,特别是在需要控制对象访问、添加额外逻辑或优化性能的场景中。 ​​核心…

【嵌入式学习3】UDP发送端、接收端

目录 1、发送端 2、接收端 3、UDP广播 1、发送端 from socket import *udp_socket socket(AF_INET,SOCK_DGRAM) udp_socket.bind(("127.0.0.1",3333))data_str "UDP发送端数据" data_bytes data_str.encode("utf-8") udp_socket.sendto(d…

AI重构SEO关键词精准布局

内容概要 在传统SEO策略面临搜索场景碎片化、用户意图复杂化的挑战下,AI技术通过多维数据分析与算法建模,正在重构关键词布局的逻辑框架。基于自然语言处理(NLP)的语义分析能力,AI可精准识别搜索词背后的需求层级&…

谷歌发布网络安全AI新模型Sec-Gemini v1

谷歌近日宣布推出实验性AI模型Sec-Gemini v1,旨在通过人工智能技术革新网络安全防御体系。该模型由Sec-Gemini团队成员Elie Burzstein和Marianna Tishchenko共同研发,旨在帮助网络安全人员应对日益复杂的网络威胁。 攻防不对称的破局之道 Sec-Gemini团队…

IntelliJ IDEA下开发FPGA——FPGA开发体验提升__下

前言 由于Quartus写代码比较费劲,虽然新版已经有了代码补全,但体验上还有所欠缺。于是使用VS Code开发,效果如下所示,代码样式和基本的代码补全已经可以满足开发,其余工作则交由Quartus完成 但VS Code的自带的git功能&…

Python语言的需求分析

Python语言的需求分析 引言 在信息技术快速发展的今天,编程语言的选择对于软件开发的成功与否起着至关重要的作用。Python作为一种高级编程语言,以其简洁易读的语法和强大的功能受到越来越多开发者的青睐。通过对Python语言的需求分析,我们…

抓wifi无线空口包之Ubuntu抓包(二)

一、设置网卡信道和频段,并抓包 1、使用iwconfig查看自己机器的无线网卡名称 wangwang-ThinkCentre-M930t-N000:~$ iwconfig lo no wireless extensions. eno1 no wireless extensions. enxc8a3624ab329 no wireless extensions. wlx90de80d1b5b1 IE…

深度学习实战电力设备缺陷检测

本文采用YOLOv11作为核心算法框架,结合PyQt5构建用户界面,使用Python3进行开发。YOLOv11以其高效的实时检测能力,在多个目标检测任务中展现出卓越性能。本研究针对电力设备缺陷数据集进行训练和优化,该数据集包含丰富的电力设备缺…