当前位置: 首页 > news >正文

JavaScript性能优化:DOM操作优化实战

JavaScript性能优化:DOM操作优化实战

一 重排与重绘的代价
问题场景

用户点击按钮后,需要动态生成一个包含10,000个选项的下拉列表,但界面出现长达5秒的冻结。

错误代码示例
function createList() {
  const ul = document.getElementById("myList");
  for(let i=0; i<10000; i++){
    const li = document.createElement("li");
    li.style.color = "red";  // 触发样式计算
    li.style.margin = "2px"; // 触发布局
    li.textContent = `选项 ${i}`;
    ul.appendChild(li);      // 每次循环都导致重排
  }
}
问题分析
  • 每次循环都修改元素样式 ➔ 触发 强制同步布局(Forced Synchronous Layout)
  • 直接操作真实DOM ➔ 累计触发 10,000次重排
二 高效DOM操作三板斧
优化方案1:文档碎片(DocumentFragment)
function createListOptimized() {
  const ul = document.getElementById("myList");
  const fragment = document.createDocumentFragment(); // 内存中的虚拟容器

  for(let i=0; i<10000; i++){
    const li = document.createElement("li");
    // 先完成所有属性设置
    li.textContent = `选项 ${i}`;
    li.className = "prestyled-item"; // 通过CSS类批量设置样式
    
    fragment.appendChild(li); // 不会触发真实DOM操作
  }

  ul.appendChild(fragment); // 仅1次重排
}
优化方案2:样式批量处理
/* 将样式集中到CSS类 */
.prestyled-item {
  color: red;
  margin: 2px;
}
优化方案3:读写分离原则
// 错误:交替读写布局属性
element.style.width = "100px";
const height = element.offsetHeight; // 触发立即计算
element.style.height = height + "px";

// 正确:先读后写
const height = element.offsetHeight; // 集中读取
element.style.width = "100px";        // 集中写入
element.style.height = height + "px";
三 事件监听器的正确姿势
内存泄漏陷阱
// 错误:为每个列表项绑定监听器
document.querySelectorAll(".item").forEach(item => {
  item.addEventListener("click", handleClick);
});

// 当需要移除元素时:
container.innerHTML = ""; // 监听器仍然残留在内存中!
优化方案:事件委托
// 正确:利用事件冒泡在父级监听
document.getElementById("container").addEventListener("click", e => {
  if(e.target.classList.contains("item")) {
    handleClick(e);
  }
});

优势对比

方式内存占用(1000个元素)初始化耗时
单独绑定1000个监听器120ms
事件委托1个监听器15ms
四 虚拟DOM的启示
核心思想
数据变化
生成虚拟DOM树
对比新旧虚拟DOM
计算最小修改
批量更新真实DOM
手动实现简化版
let vDOM = { type: 'ul', children: [] };

// 更新函数
function updateDOM() {
  const realDOM = document.createElement(vDOM.type);
  vDOM.children.forEach(child => {
    const node = document.createElement(child.type);
    node.textContent = child.content;
    realDOM.appendChild(node);
  });
  
  // 批量替换
  document.getElementById("app").replaceChildren(realDOM);
}

// 添加新项时:
vDOM.children.push({ type: 'li', content: '新项目' });
requestAnimationFrame(updateDOM); // 在下一次重绘时集中更新

本章重点总结

  1. 批量操作:使用文档碎片减少DOM操作次数
  2. 样式管理:用CSS类替代直接样式操作
  3. 事件优化:委托模式节省内存
  4. 更新策略:集中修改减少重排次数

相关文章:

  • 2025-03-10 吴恩达机器学习1——机器学习概述
  • Python的函数
  • OpenPLC WebSever启动
  • kali linux 漏洞扫描
  • 关于原码、反码、补码、移码
  • 【亲测可行】rk3588交叉编译opencv-4.5.1,ffmpeg-4.2.9,x264
  • Hugging Face的Transformers核心模块:Pipelines(参数说明,各种模型类型调用案例)
  • TypeScript基础类型详解:与JavaScript的对比与核心价值
  • 【Android】03-Android 开发机器配置要求
  • 【day12】进程切换与调度:linux系统的幕后操控术
  • 项目实操分享:一个基于 Flask 的音乐生成系统,能够根据用户指定的参数自动生成 MIDI 音乐并转换为音频文件
  • 可视化绘图技巧100篇进阶篇(十八)-鸡冠花图
  • 18 HarmonyOS NEXT UVList组件开发指南(五)
  • AI+办公 Task1
  • `bitsandbytes` 是什么? 有支持 CPU 的版本吗
  • NVIDIA k8s-device-plugin源码分析与安装部署
  • 数学 二次函数
  • 人工智能技术篇*卷(一)
  • 从0开始的操作系统手搓教程33:挂载我们的文件系统
  • boost::beast websocket 实例
  • 媒体:演员黄杨钿甜耳环事件仍有三大疑问待解
  • 俄乌上周在土耳其直接谈判,外交部回应
  • 四大皆空!赛季还没结束,曼城已经吃上“散伙饭”了
  • 首次带人形机器人走科技节红毯,傅利叶顾捷:没太多包袱,很多事都能从零开始
  • 机器人为啥热衷“搞体育”,经济日报:是向加速融入日常生活发起的冲锋
  • 官方通报汕头违建豪宅“英之园”将强拆:对有关人员严肃追责问责