• 如果后端返回了十万条数据要你插入到页面中,你会怎么处理?


    当面临需要插入大量数据到页面的情况时,下面是一些建议的处理方法:

    1. 分页加载:考虑将数据分成多个页面,每次只加载当前页面所需的数据。这样可以减少一次性加载大量数据对页面性能的影响,并提供更好的用户体验

    2. 虚拟滚动:使用虚拟滚动技术,只渲染当前可见区域的数据,而不是全部渲染。这可以显著减少渲染时的性能开销,并提高滚动时的响应速度。

    3. 延迟加载:只在用户需要时加载数据。例如,当用户滚动到页面底部时,再加载下一页的数据。这样可以逐步加载数据,减轻页面的负担。

    4. 后台分页查询:考虑在后端实现分页查询,只返回当前页所需的数据量。通过限制每次请求的数据量,可以减少数据传输和页面渲染的时间。

    5. 数据缓存:如果数据是经常被使用的,并且不经常变化,可以考虑在前端进行数据缓存。这样可以避免每次加载都从后端请求数据,提高页面的加载速度。

    以上这些方法可以根据具体的场景和需求进行组合使用。重要的是权衡性能和用户体验,确保页面加载和操作的流畅性。

    下面是我使用的 时间分片来处理

    通过 setTimeout

    直接上一个例子:

    <!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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

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

    在这里插入图片描述
    但是很明显能看到的问题是,快速拖动滚动条时,数据列表中会有闪烁的情况

    这是因为:

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

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

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

    通过 requestAnimationFrame

    <!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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    在这里插入图片描述
    很明显,闪烁的问题被解决了

    这是因为:

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

    在这里插入图片描述

  • 相关阅读:
    数据结构的一些算法
    Chrome浏览器怎么清理单个页面缓存,简单实用
    使用JS代理 实现大对象的功能拆解
    7.22 SpringBoot项目实战【收藏 和 取消收藏】
    统一所有 LLM API:支持预算与速率限制 | 开源日报 No.229
    arrow(c++)改写empyrical系列1---用arrow读取基金净值数据并计算夏普率
    java,mqtt-client开发创建客户端
    基于jacoco和CI做代码覆盖率检测
    Javascript专项练习
    AI视频教程下载:给初学者的ChatGPT提示词技巧
  • 原文地址:https://blog.csdn.net/qq_41961239/article/details/133879323