前端性能优化之同时插入100000个元素页面不卡顿

news2025/3/6 19:20:23

面试官:同时插入100000个元素怎么让页面不卡顿

优化前写法

首先我们来看下面的一段,点击按钮后,循环100000次,每次都插入一个元素,并且插入区域上方还有一个小球在滚动,在插入的过程中我们可以观察小球的动画是否出现卡顿

<template>
    <h3>小球左右上下循环移动动画</h3>
    <div class="container">
      <div id="ball" class="ball"></div>
    </div>

    <h3>前端性能优化之</h3>
    <el-button type="primary" @click='addBall'>加载10000个小球</el-button>
    <div id='ballBox' class='ballBox'></div>
</template>

<script setup>
 onMounted(() => {
  const ball = document.getElementById('ball')
  const container = document.querySelector('.container')

  // 获取容器的宽高
  const containerWidth = container.offsetWidth
  const containerHeight = container.offsetHeight

  // 小球的初始位置和速度
  let ballX = 0
  let ballY = 0
  let speedX = 2 // 水平速度
  let speedY = 2 // 垂直速度

  // 动画函数
  function moveBall() {
    // 更新小球的位置
    ballX += speedX
    ballY += speedY

    // 检测边界碰撞并反转方向
    if (ballX <= 0 || ballX + ball.offsetWidth >= containerWidth) {
      speedX = -speedX
    }
    if (ballY <= 0 || ballY + ball.offsetHeight >= containerHeight) {
      speedY = -speedY
    }

    // 应用新的位置
    ball.style.left = `${ballX}px`
    ball.style.top = `${ballY}px`

    // 循环调用动画
    requestAnimationFrame(moveBall)
  }

  // 启动动画
  moveBall()
})

function addBall(){
  let ballBox = document.getElementById('ballBox')
  const tasks = Array.from({ length: 100000 }, (_, i) => {
    return () => {
      let ball = document.createElement('div')
      ball.innerText = i + 1
      ballBox.appendChild(ball)
    }
  })
  for (let i = 0; i < tasks.length; i++) {
    tasks[i]()
  }
}
</script>

<style scoped>
.container {
  position: relative;
  width: 400px;
  height: 300px;
  border: 2px solid #ccc;
  background-color: #f5f5f5;
  overflow: hidden; /* 防止小球超出容器 */
}

.ball {
  position: absolute;
  width: 30px;
  height: 30px;
  background-color: red;
  border-radius: 50%; /* 圆形 */
}
</style>

目前的效果

gifimg2

可以看到点击后小球明显的出现了一段时间的卡顿才恢复正常

使用DocumentFragment减少DOM操作

DocumentFragment 是一个轻量级的文档对象,可以作为一个临时的容器来存储一组节点。它的主要优点是可以减少对 DOM 的多次操作,从而提高性能。我们可以将多个节点添加到 DocumentFragment 中,然后一次性将 DocumentFragment 添加到 DOM 中。从而较少浏览器的重绘和回流

改写代码如下

function addBall() {
  // 获取要添加小球的容器元素
  let ballBox = document.getElementById('ballBox')
  
  // 创建一个 DocumentFragment,用于批量添加小球
  const fragment = document.createDocumentFragment()
  
  // 创建一个包含 100000 个任务的数组,每个任务用于创建一个小球并添加到 fragment 中
  const tasks = Array.from({ length: 100000 }, (_, i) => {
    return () => {
      // 创建一个 div 元素表示小球
      let ball = document.createElement('div')
      // 设置小球的文本内容为其序号
      ball.innerText = i + 1
      // 将小球添加到 fragment 中
      fragment.appendChild(ball)
    }
  })
  
  // 执行所有任务,将小球添加到 fragment 中
  for (let i = 0; i < tasks.length; i++) {
    tasks[i]()
  }
  
  // 将 fragment 添加到 ballBox 中
  ballBox.appendChild(fragment)
}

但是效果依然不是很理想

使用requestIdleCallback利用空闲时间渲染

requestIdleCallback 是一个浏览器 API,它允许你在浏览器空闲时执行一些低优先级的任务。我们可以使用它来优化 addBall 函数中的任务调度,以避免阻塞主线程。

另外结合DocumentFragment减少重绘共同作用优化渲染问题,下面的优化后的代码

function addBall() {
  // 获取要添加小球的容器元素
  let ballBox = document.getElementById('ballBox')
  
  // 创建一个 DocumentFragment,用于批量添加小球
  const fragment = document.createDocumentFragment()
  
  // 创建一个包含 10000 个任务的数组,每个任务用于创建一个小球并添加到 fragment 中
  const tasks = Array.from({ length: 10000 }, (_, i) => {
    return () => {
      // 创建一个 div 元素表示小球
      let ball = document.createElement('div')
      // 设置小球的文本内容为其序号
      ball.innerText = i + 1
      // 将小球添加到 fragment 中
      fragment.appendChild(ball)
    }
  })

  // 定义一个函数用于执行任务
  function performTasks(tasks) {
    // 如果任务数组为空,则将 fragment 添加到 ballBox 中
    if (tasks.length === 0) {
      ballBox.appendChild(fragment)
      return
    }

    // 使用 requestIdleCallback 在浏览器空闲时执行任务
    requestIdleCallback((deadline) => {
      // 当浏览器有空闲时间且任务数组不为空时,执行任务
      while (deadline.timeRemaining() > 0 && tasks.length > 0) {
        // 从任务数组中取出一个任务并执行
        const task = tasks.shift()
        task()
      }
      // 递归调用 performTasks 以继续执行剩余的任务
      performTasks(tasks)
    })
  }

  // 开始执行任务
  performTasks(tasks)
}

deadline.timeRemaining()requestIdleCallback 回调函数的参数 deadline 提供的方法之一。它返回当前空闲周期中剩余的毫秒数。这个方法允许你检查在当前空闲周期中还剩下多少时间可以用来执行任务

deadline.timeRemaining() 大于0表示还有空闲时间,利用这个时间来渲染小球,从而不会阻塞主线程,从而保持页面的响应性。

优化后的效果

gifimg3

可以看到,小球轻微的卡顿一下就接着继续运行

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

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

相关文章

Exoplayer2源码编译FFmpeg拓展模块实现音频软解码

在前面文章最新版本Exoplayer扩展FFmpeg音频软解码保姆级教程中介绍了最新版本的Exoplayer(androidx.Media3)编译FFmpeg模块的流程&#xff0c;有就是media3版本的explayer最低支持的sdk版本是21也就是Android5.x,但是市面上还是有很多IOT设备是很老的android4.4(sdk19)的&…

Docker安装嵌入框架Text Embeddings Inference (TEI)

Docker安装Text Embeddings Inference (TEI) 1 简单介绍 文本嵌入推理&#xff08;TEI&#xff0c;Text Embeddings Inference &#xff09;是HuggingFace研发的一个用于部署和服务开源文本嵌入和序列分类模型的工具包。TEI兼容OpenAI的嵌入模型的规范。 # 官网地址 https:/…

MAUI(C#)安卓开发起步

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

PPT小黑第26套

对应大猫28 层次级别是错的&#xff0c;看着是十页&#xff0c;导入ppt之后四十多页 选中所有 红色蓝色黑色 文本选择标题&#xff1a;选择 -格式相似文本&#xff08;检查有没有漏选 漏选的话 按住ctrl 点下一个&#xff09; 要求新建幻灯片中不包含原素材中的任何格式&…

【Linux-网络】HTTP的清风与HTTPS的密语

&#x1f3ac; 个人主页&#xff1a;谁在夜里看海. &#x1f4d6; 个人专栏&#xff1a;《C系列》《Linux系列》《算法系列》 ⛰️ 道阻且长&#xff0c;行则将至 目录 &#x1f4da; 引言 &#x1f4da; 一、HTTP &#x1f4d6; 1.概述 &#x1f4d6; 2.URL &#x1f5…

解决docker认证问题 failed to authorize: failed to fetch oauth token

报错信息[bash1]解决方案 全局代理打开“buildkit”: false &#xff0c;见[图1] [bash1] >docker build -t ffpg . [] Building 71.8s (3/3) FINISHED docker:desktop-linux> [internal] load bui…

无人机应用探索:玻纤增强复合材料的疲劳性能研究

随着无人机技术的快速发展&#xff0c;轻量化已成为其结构设计的核心需求。玻纤增强复合材料凭借高强度、低密度和优异的耐环境性能&#xff0c;成为无人机机身、旋翼支架等关键部件的理想选择。然而&#xff0c;无人机在服役过程中需应对复杂多变的环境&#xff1a;高空飞行时…

Visual Studio工具

高亮显示匹配的标签&#xff08;小括号&#xff0c;中括号&#xff0c;大括号&#xff09;

STM32Cubemx配置E22-xxxT22D lora模块实现定点传输

文章目录 一、STM32Cubemx配置二、定点传输**什么是定点传输&#xff1f;****定点传输的特点****定点传输的工作方式****E22 模块定点传输配置****如何启用定点传输&#xff1f;****示例** **应用场景****总结** **配置 1&#xff1a;C0 00 07 00 02 04 62 00 17 40****解析** …

WPF+WebView 基础

1、基于.NET8&#xff0c;通过NuGet添加Microsoft.Web.WebView2。 2、MainWindow.xaml代码如下。 <Window x:Class"Demo.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/win…

蓝桥杯算法——铠甲合体

问题描述 暗影大帝又开始搞事情了&#xff01;这次他派出了 MM 个战斗力爆表的暗影护法&#xff0c;准备一举摧毁 ERP 研究院&#xff01;MM 个暗影护法的战斗力可分别用 B1,⋯,BMB1​,⋯,BM​ 表示。 ERP 研究院紧急召唤了 NN 位铠甲勇士前来迎战&#xff01;每位铠甲勇士都…

docker:Dockerfile案例之自定义centos7镜像

1 案例需求 自定义centos7镜像。要求&#xff1a; 默认登录路径为 /usr可以使用vim 2 实施步骤 编写dockerfile脚本 vim centos_dockerfile 内容如下&#xff1a; #定义父镜像 FROM centos:7#定义作者信息 MAINTAINER handsome <handsomehandsome.com># 设置阿里云…

学习笔记:IC存储总结(ROM,RAM, EEPROM, Flash, SRAM, DRAM, DDL)

一&#xff0c;概述 半导体存储器是一种可以存储大量二值信息的半导体器件。在电子计算机及一些其他的数字系统的工作过程中&#xff0c;需要对大量的数据进行储存。由于数据处理的数据量和运算速度的要求&#xff0c;因此把存储量和存取速度作为衡量存储器的重要指标。 在电子…

Scala:统计每个单词出现的个数并打印

目录 问题拆解&#xff1a; 解题步骤&#xff1a; 1. 拆分所有字符串为单词 2. 遍历所有单词并统计 3. 打印结果 基础版代码实现&#xff1a; 代码解释&#xff1a; 输出结果&#xff1a; 为什么这样设计&#xff1f; 继承的APP是个啥&#xff1f; 使用高阶函数式编…

C++前缀和

个人主页&#xff1a;[PingdiGuo_guo] 收录专栏&#xff1a;[C干货专栏] 大家好&#xff0c;今天我们来了解一下C的一个重要概念&#xff1a;前缀和 目录 1.什么是前缀和 2.前缀和的用法 1.前缀和的定义 2.预处理前缀和数组 3.查询区间和 4.数组中某个区间的和是否为特定…

图解MOE大模型的7个核心问题并探讨DeepSeekMoE的专家机制创新

原文地址:https://newsletter.maartengrootendorst.com/p/a-visual-guide-to-mixture-of-experts #mermaid-svg-FU7YUSIfuXO6EVHa {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-FU7YUSIfuXO6EVHa .error-icon{fill…

SpringBoot项目集成ElasticSearch

1. 项目背景 处于失业找工作的阶段&#xff0c;随便写写吧~ 没啥背景&#xff0c;没啥意义&#xff0c;Java后端越来越卷了。第一学历不是本科&#xff0c;感觉真的是没有一点路可走。 如果有路过的小伙伴&#xff0c;如果身边还有坑位&#xff0c;不限第一学历的话&#xff0…

DeepSeek大模型深度解析:架构、技术与应用全景

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。https://www.captainbed.cn/north 文章目录 一、大模型时代与DeepSeek的定位1.1 大模型发展历程回顾大模型发展历程时间轴&#xff08;20…

Dubbo+Zookeeper

Apache ZooKeeper 通过当前页面下载Zookeeper 在这里启动zookeeper 可以根据这个页面简单学习一下&#xff0c;但是没有集成mysql&#xff0c;也会出现一些报错&#xff0c;且在这之后我们要使用的管理页面是vue的dubbo-admin dubbo学习三&#xff1a;springboot整合dubbozo…

从厨电模范到数字先锋,看永洪科技如何助力方太集团开启数字新征程

在数字化洪流席卷全球的宏大背景下&#xff0c;企业转型升级的紧迫性与重要性日益凸显&#xff0c;成为驱动行业进步的关键引擎。在这一波澜壮阔的转型浪潮中&#xff0c;方太集团——厨电领域的璀璨明珠&#xff0c;以其前瞻性的战略视野和不懈的创新精神&#xff0c;携手数据…