面试题-渲染一万条数据

简介: 面试题-渲染一万条数据

最近一直听到一道面试题,即:后端返回10000条数据,前端怎么渲染到页面上?

首先想到的应该是分批处理,比如每次处理10条或者20条,然后处理的逻辑放到setTimeout里面,这样不会阻塞主逻辑和页面渲染。


所以第一版代码如下:


<h1>渲染一万条数据</h1>
<a href="https://baidu.com" target="_blank">百度一下</a>
<ul class="content"></ul>
<script>
  console.log(1);  
  // 总数据  
  const total = 10000, 
  // 每次处理数据  
  each = 20,  
  // 需要处理次数  
  needTimes = Math.ceil(total / each),  
  // 父容器
  content = document.querySelector('.content')  
  // 当前处理次数
  let currentTime = 0
  // 处理元素插入  
  function add() {    
    setTimeout(() =>{      
    console.log(3);     
     for (let i = 0; i < each; i++) { 
       const li = document.createElement('li')
       li.innerText = Math.floor(i+currentTime*each)
       content.appendChild(li)
      }
      currentTime++;
      if (currentTime < needTimes) add();
    },1000/60)
  }  
  add();
  console.log(2)
</script>
复制代码


我们观察上面的代码,可以优化的点是add方法中的插入操作,我们知道元素的插入会消耗浏览器性能并引起页面重排,那我们把每次需要处理的元素收集起来,进行一次插入操作,这样相比之前单个元素插入就要好一些,但是这个时候如果用普通的Dom元素就会造成我们不需要的层级嵌套,有没有一个好的方法解决这个问题呢?


答案就是createDocumentFragment


该方法创建一个新的空白的文档片段,使用方法如下:


let fragment = document.createDocumentFragment();
复制代码


fragment 是一个指向空DocumentFragment对象的引用,DocumentFragments 是DOM节点。它们不是主DOM树的一部分。


通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树,在DOM树中,文档片段被其所有的子元素所代替。


因为文档片段存在于内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面重排。


因此,使用文档片段通常会带来更好的性能。


优化后的代码如下:


<h1>渲染一万条数据</h1>
<a href="https://baidu.com" target="_blank">百度一下</a>
<ul class="content"></ul><script>
  console.log(1);
  // 总数据
  const total = 10000,
  // 每次处理数据
  each = 20,
  // 需要处理次数
  needTimes = Math.ceil(total / each),
  // 父容器
  content = document.querySelector('.content')
  // 当前处理次数
  let currentTime = 0
  // 处理元素插入
  function add() {
    setTimeout(() =>{
      console.log(3);
      const fragment = document.createDocumentFragment()
      for (let i = 0; i < each; i++) {
        const li = document.createElement('li')
        li.innerText = Math.floor(i+currentTime*each)
        fragment.appendChild(li)
      }
      content.appendChild(fragment)
      currentTime++;
      if (currentTime < needTimes) {
        add();
      }
    },1000/60)
  }
  add();
  console.log(2)
</script>
复制代码


接下来我们主逻辑中能优化的点就是setTimeout了,我们知道setTimeout的执行时间会受到任务队列影响,并不一定完全按照第二个参数设置的毫秒数执行,而且上面我们设置了间隔时间假定为一秒60帧,是写死的。那针对这一部分我们有什么办法优化呢?


答案就是requestAnimationFrame


window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画


该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行


注意:若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用window.requestAnimationFrame()


那它有什么优点呢?


1、requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或重排中完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。由系统决定回调函数的执行时机,不会引起丢帧,不会卡顿


2、在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这就意味着更少的的CPU,GPU和内存使用量


3、requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销


优化后的代码如下:


<h1>渲染一万条数据</h1>
<a href="https://baidu.com" target="_blank">百度一下</a>
<ul class="content"></ul>
<script>
  console.log(1);
  // 总数据
  const total = 10000,
  // 每次处理数据
  each = 20,
  // 需要处理次数
  needTimes = Math.ceil(total / each),
  // 父容器
  content = document.querySelector('.content')
  // 当前处理次数
  let currentTime = 0
  // 处理元素插入
  function add() {
    console.log(3);
    const fragment = document.createDocumentFragment()
    for (let i = 0; i < each; i++) {
      const li = document.createElement('li')
      li.innerText = Math.floor(i+currentTime*each)
      fragment.appendChild(li)
    }
    content.appendChild(fragment)
    currentTime++;
    if (currentTime < needTimes) {
      window.requestAnimationFrame(add)
    }
  }
  window.requestAnimationFrame(add)
  console.log(2)
</script>
复制代码


至此,个人认为就是比较完美的答案了,相关特性大家可以copy代码测试一下,本人亲测有效


如果您有更好的方法,欢迎评论区讨论!感谢阅读!

相关文章
|
5月前
|
SQL 分布式计算 监控
Sqoop数据迁移工具使用与优化技巧:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入解析Sqoop的使用、优化及面试策略。内容涵盖Sqoop基础,包括安装配置、命令行操作、与Hadoop生态集成和连接器配置。讨论数据迁移优化技巧,如数据切分、压缩编码、转换过滤及性能监控。此外,还涉及面试中对Sqoop与其他ETL工具的对比、实际项目挑战及未来发展趋势的讨论。通过代码示例展示了从MySQL到HDFS的数据迁移。本文旨在帮助读者在面试中展现Sqoop技术实力。
320 2
|
5月前
|
SQL 缓存 easyexcel
面试官问10W 行级别数据的 Excel 导入如何10秒处理
面试官问10W 行级别数据的 Excel 导入如何10秒处理
232 0
|
5月前
|
编解码 移动开发 前端开发
【面试题】 给你十万条数据,怎么样顺滑的渲染出来?
【面试题】 给你十万条数据,怎么样顺滑的渲染出来?
|
5月前
|
前端开发 JavaScript
【面试题】面试官:如果后端给你 1w 条数据,你如何做展示?
【面试题】面试官:如果后端给你 1w 条数据,你如何做展示?
|
5月前
|
SQL 前端开发 程序员
【面试题】前端开发中如何高效渲染大数据量?
【面试题】前端开发中如何高效渲染大数据量?
113 0
|
2月前
|
Java
【Java基础面试五】、 int类型的数据范围是多少?
这篇文章回答了Java中`int`类型数据的范围是-2^31到2^31-1,并提供了其他基本数据类型的内存占用和数值范围信息。
【Java基础面试五】、 int类型的数据范围是多少?
|
3月前
|
canal 缓存 NoSQL
Redis常见面试题(一):Redis使用场景,缓存、分布式锁;缓存穿透、缓存击穿、缓存雪崩;双写一致,Canal,Redis持久化,数据过期策略,数据淘汰策略
Redis使用场景,缓存、分布式锁;缓存穿透、缓存击穿、缓存雪崩;先删除缓存还是先修改数据库,双写一致,Canal,Redis持久化,数据过期策略,数据淘汰策略
Redis常见面试题(一):Redis使用场景,缓存、分布式锁;缓存穿透、缓存击穿、缓存雪崩;双写一致,Canal,Redis持久化,数据过期策略,数据淘汰策略
|
2月前
|
存储 负载均衡 算法
[go 面试] 一致性哈希:数据分片与负载均衡的黄金法则
[go 面试] 一致性哈希:数据分片与负载均衡的黄金法则
|
2月前
|
缓存 网络协议 JavaScript
面试常考题:输入url到页面渲染发生了什么?(前半段)
面试常考题:输入url到页面渲染发生了什么?(前半段)
|
2月前
|
JavaScript 前端开发 网络协议
面试常考题: 输入url到页面渲染发生了什么(后半段)
面试常考题: 输入url到页面渲染发生了什么(后半段)
下一篇
无影云桌面