前端时间分片渲染

news2024/11/17 9:28:15

在经典的面试题中:”如果后端返回了十万条数据要你插入到页面中,你会怎么处理?

除了像 useVirtualList 这样的虚拟列表来处理外,我们还可以通过 时间分片 来处理

通过 setTimeout

直接上一个例子:

<!--
 * @Author: Jolyne
 * @Date: 2023-09-22 15:45:45
 * @LastEditTime: 2023-09-22 15:47:24
 * @LastEditors: Jolyne
 * @Description: 
-->
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>十万数据渲染</title>
</head>

<body>
  <ul id="list-container"></ul>

  <script>
    const oListContainer = document.getElementById('list-container')

    const fetchData = () => {
      return new Promise(resolve => {
        const response = {
          code: 0,
          msg: 'success',
          data: [],
        }

        for (let i = 0; i < 100000; i++) {
          response.data.push(`content-${i + 1}`)
        }

        setTimeout(() => {
          resolve(response)
        }, 100)
      })
    }

    // 模拟请求后端接口返回十万条数据
    // 渲染 total 条数据中的第 page 页,每页 pageCount 条数据
    const renderData = (data, total, page, pageCount) => {
      // base case -- total 为 0 时没有数据要渲染 不再递归调用
      if (total <= 0) return

      // total 比 pageCount 少时只渲染 total 条数据
      pageCount = Math.min(pageCount, total)

      setTimeout(() => {
        const startIdx = page * pageCount
        const endIdx = startIdx + pageCount
        const dataList = data.slice(startIdx, endIdx)

        // 将 pageCount 条数据插入到容器中
        for (let i = 0; i < pageCount; i++) {
          const oItem = document.createElement('li')
          oItem.innerText = dataList[i]
          oListContainer.appendChild(oItem)
        }

        renderData(data, total - pageCount, page + 1, pageCount)
      }, 0)
    }

    fetchData().then(res => {
      renderData(res.data, res.data.length, 0, 200)
    })

  </script>
</body>

</html>

上面的例子中,我们使用了 setTimeout,在每一次宏任务中插入一页数据,然后设置多个这样地宏任务,直到把所有数据都插入为止。

图片

但是很明显能看到的问题是,快速拖动滚动条时,数据列表中会有闪烁的情况

这是因为:

当使用 setTimeout 来拆分大量的 DOM 插入操作时,虽然我们将延迟时间设置为 0ms,但实际上由于 JavaScript 是单线程的,任务执行时会被放入到事件队列中,而事件队列中的任务需要等待当前任务执行完成后才能执行。所以即使设置了 0ms 延迟,setTimeout 的回调函数也不一定会立即执行,可能会受到其他任务的阻塞。

当 setTimeout 的回调函数执行的间隔超过了浏览器每帧更新的时间间隔(一般是 16.7ms),就会出现丢帧现象。丢帧指的是浏览器在更新页面时,没有足够的时间执行全部的任务,导致部分任务被跳过,从而导致页面渲染不连续,出现闪烁的情况

所以,我们改善一下,通过 requestAnimationFrame 来处理

通过 requestAnimationFrame

<!--
 * @Author: Jolyne
 * @Date: 2023-09-22 15:45:45
 * @LastEditTime: 2023-09-22 15:47:24
 * @LastEditors: Jolyne
 * @Description: 
-->
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>直接插入十万条数据</title>
</head>

<body>
  <ul id="list-container"></ul>

  <script>
    const oListContainer = document.getElementById('list-container')

    const fetchData = () => {
      return new Promise(resolve => {
        const response = {
          code: 0,
          msg: 'success',
          data: [],
        }

        for (let i = 0; i < 100000; i++) {
          response.data.push(`content-${i + 1}`)
        }

        setTimeout(() => {
          resolve(response)
        }, 100)
      })
    }

    // 模拟请求后端接口返回十万条数据
    // 渲染 total 条数据中的第 page 页,每页 pageCount 条数据
    const renderData = (data, total, page, pageCount) => {
      // base case -- total 为 0 时没有数据要渲染 不再递归调用
      if (total <= 0) return

      // total 比 pageCount 少时只渲染 total 条数据
      pageCount = Math.min(pageCount, total)

      requestAnimationFrame(() => {
        const startIdx = page * pageCount
        const endIdx = startIdx + pageCount
        const dataList = data.slice(startIdx, endIdx)

        // 将 pageCount 条数据插入到容器中
        for (let i = 0; i < pageCount; i++) {
          const oItem = document.createElement('li')
          oItem.innerText = dataList[i]
          oListContainer.appendChild(oItem)
        }

        renderData(data, total - pageCount, page + 1, pageCount)
      })
    }

    fetchData().then(res => {
      renderData(res.data, res.data.length, 0, 200)
    })

  </script>
</body>

</html>

图片

很明显,闪烁的问题被解决了

这是因为:

requestAnimationFrame 会在浏览器每次进行页面渲染时执行回调函数,保证了每次任务的执行间隔是稳定的,避免了丢帧现象。所以在处理大量 DOM 插入操作时,推荐使用 requestAnimationFrame 来拆分任务,以获得更流畅的渲染效果

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

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

相关文章

苹果遭双重暴击,品控翻车致iPhone15价格暴跌千元,比iPhone14更便宜

苹果近期可谓屋漏偏逢连夜雨&#xff0c;上市销售才不到一个月&#xff0c;就在中国市场被国产5G手机击败&#xff0c;日前第三方渠道对iPhone15的报价也持续下跌&#xff0c;其中iPhone15plus更是下跌超千元&#xff0c;显示出iPhone15似乎真的卖不动了。 据第三方渠道的报价显…

面试官:如何理解CDN?说说实现原理?

一、是什么 CDN (全称 Content Delivery Network)&#xff0c;即内容分发网络 构建在现有网络基础之上的智能虚拟网络&#xff0c;依靠部署在各地的边缘服务器&#xff0c;通过中心平台的负载均衡、内容分发、调度等功能模块&#xff0c;使用户就近获取所需内容&#xff0c;降…

51系列—基于51单片机的电子万年历设计

本文主要介绍基于51单片机的电子万年历设计 前言 电子万年历是单片机系统的一个应用&#xff0c;由硬件和软件相配合使用。硬件由主控器、时钟电路、温度检测电路、显示电路、键盘接口5个模块组成。主控模块用AT89C52、时钟电路用时钟芯片DS1302、显示模块用LED数码管、温度检…

【CGSSA-BP预测】基于混合混沌-高斯变异-麻雀算法优化BP神经网络回归预测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

关于ibatis的一些用法——1(基本语法)

关于ibatis的一些用法——1&#xff08;基本语法&#xff09; 1. 前言1.1 唠叨1.2 官网1.2.1 官网地址1.2.2 价值文档1.2.2.1 Data Mapper1.2.2.2 其他 1.3 价值 IT技术问答网站 2. 基本语法2.1 关于 in 的用法2.2 关于驼峰问题2.3 3. 1. 前言 1.1 唠叨 本不想整这些老框架的…

在edge浏览器中安装好了burp的ca证书,浏览器依旧不能访问https的原因

在edge浏览器中安装好了burp的ca证书&#xff0c;浏览器依旧不能访问https的原因 1.SwitchyOmega代理插件设置2.CA证书方法1方法2 1.SwitchyOmega代理插件设置 严格安装以下图片执行&#xff0c;不可少写或多写 2.CA证书 方法1 下载好证书&#xff0c;先导入到edge浏览器的中…

商业智能的利用:打造成功的业务战略之道

在当今快节奏和数据驱动的商业环境中&#xff0c;制定稳健的商业战略对于实现可持续的增长和保持竞争力至关重要。商业智能&#xff08;BI&#xff09;是能够显著提高业务战略有效性的关键因素之一。本文将深入探讨商业智能的定义、其在战略制定中的重要性&#xff0c;以及如何…

作为资深IT从业者,我高度推荐这款智能团队协作工具

作为一名资深的IT从业人员,我最近发现了一款非常不错的团队协作和远程办公工具,它可以大大提高企业和团队的工作效率,所以今天我就向大家强烈推荐下这款产品。 这款产品名叫TeamLinker,它是一个集成了项目管理、文档协同、视频会议等多种功能于一体的智能化团队协作平台。以下…

数控设备液压站比例阀放大器

数控设备液压站是由液压泵、驱动用电动机、油箱、方向阀、节流阀、溢流阀等构成的液压源装置或包括控制阀在内的液压装置。电机带动油泵旋转&#xff0c;从油箱中吸油后打油&#xff0c;将机械能转化为液压油的压力能&#xff0c;再通过集成块&#xff08;或阀组合&#xff09;…

中文编程开发语言编程实际案例:程序控制灯电路以及桌球台球室用这个程序计时计费

中文编程开发语言编程实际案例&#xff1a;程序控制灯电路以及桌球台球室用这个程序计时计费 上图为&#xff1a;程序控制的硬件设备电路图 上图为&#xff1a;程序控制灯的开关软件截图&#xff0c;适用范围比如&#xff1a;台球厅桌球室的计时计费管理&#xff0c;计时的时候…

一阶惯性滤波器的传递函数与时域实现

滤波前后的效果对比如下&#xff1a; 可以得到&#xff0c;滤波后的幅值刚好是滤波前的0.707倍&#xff0c;也就是衰减了3deb&#xff0c;与理论分析一致。 需要注意的是&#xff0c;在simulink中&#xff0c;时域执行周期需要与设置的采样周期Ts一致&#xff0c;例如本例&…

智慧公厕:革新性的公共厕所管理系统

公共厕所&#xff0c;多年前似乎对每个人来说都是个需要避之唯恐不及的地方。但是&#xff0c;现代科技的进步让我们对公厕的认识产生了新的转变。智慧公厕作为一种结合了现代科技和人性化设计的公共厕所信息化管理系统&#xff0c;旨在提供更高效的管理方式&#xff0c;以及更…

Jmeter(七):jmeter连接数据库/中元件的执行顺序作用域详解

Jmeter&#xff1a;jmeter连接数据库 jmeter连接mysql数据库 大致步骤如下&#xff1a; 下载mysql的jar包放入到jmeter的lib下&#xff0c;然后重启jmeter配置JDBC Connection Configuration配置JDBC Request在请求中引用查询到的结果变量&#xff0c;可以结合计数器取每一个…

怎么恢复移走的u盘数据?可以尝试这三种方法

当意外移走U盘上的数据时&#xff0c;我们常常会感到焦虑和失望&#xff0c;特别是当这些数据对我们仍然重要时。不过&#xff0c;您不必完全放弃&#xff0c;因为本文将介绍一些方法&#xff0c;以帮助您恢复U盘上的重要数据。 图片来源于网络&#xff0c;如有侵权请告知 移走…

绘制核密度估计图

简介 核密度估计图&#xff08;Kernel Density Estimation&#xff0c;KDE&#xff09;是一种用于估计数据分布的非参数方法&#xff0c;通常用于可视化和理解数据的分布情况。它通过平滑地估计数据的概率密度函数&#xff08;PDF&#xff09;来显示数据的分布特征&#xff0c…

【广州华锐互动】全屋智能家电VR虚拟仿真演示系统

在过去的几年中&#xff0c;智能家居的概念已经逐渐进入人们的生活。然而&#xff0c;它的真正潜力和最终形态可能还未被完全发掘。一种新兴的技术&#xff0c;虚拟现实&#xff08;VR&#xff09;&#xff0c;为我们提供了一种全新的方式来理解和体验智能家居。VR公司广州华锐…

C语言——二周目——程序的翻译与执行环境

一、程序环境 对于一个C语言程序的实现&#xff0c;整个过程一般存在两个不同的环境&#xff0c;分别是翻译环境与执行环境。在翻译环境中&#xff0c;我们所写的源代码经过一系列处理被转换成为可执行的机器指令&#xff1b;在执行环境中&#xff0c;会实际执行代码。 整个程序…

基于YOLOv8模型和WiderPerson数据集的行人目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型和WiderPerson数据集的行人目标检测系统可用于日常生活中检测与定位行人目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标…

该方法仅能传入 lambda 表达式产生的合成类

说明&#xff1a;使用Mybatis-plus查询记录时&#xff0c;出现下面的错误&#xff1b; org.apache.ibatis.builder.BuilderException: Error evaluating expression ew.sqlSegment ! null and ew.sqlSegment ! and ew.nonEmptyOfWhere. Cause: org.apache.ibatis.ognl.OgnlEx…

2016-2023全国MBA国家A类线趋势图:浙大MBA要高多少?

距离2024年MBA联考还有两个月左右的时间&#xff0c;冲刺阶段需要为目标做最后的努力。关于分数的目标&#xff0c;目前国外的大多数MBA项目的录取门槛都是国家A类线&#xff0c;而后续常规批复试后的调剂门槛多数也是国家A类线&#xff0c;所以国家线应该是多数考生的第一目标…