Js实现渲染上万条数据页面不卡住

setTimeout(() => {
  // 插入十万条数据
  const total = 100000;
  // 一次插入的数据
  const once = 20;
  // 插入数据需要的次数
  const loopCount = Math.ceil(total / once);
  let countOfRender = 0;
  const ul = document.querySelector('ul');
  // 添加数据的方法
  function add() {
    const fragment = document.createDocumentFragment();
    for(let i = 0; i < once; i++) {
      const li = document.createElement('li');
      li.innerText = Math.floor(Math.random() * total);
      fragment.appendChild(li);
    }
    ul.appendChild(fragment);
    countOfRender += 1;
    loop();
  }
  function loop() {
    if(countOfRender < loopCount) {
      window.requestAnimationFrame(add);
    }
  }
  loop();
}, 0)

原理:渲染大数据时,合理使用createDocumentFragment和requestAnimationFrame,将操作切分为一小段一小段执行。

documentFragment:

    是一个虚拟的Dom列表,可以储存待处理的xml片段(el元素),因为他不在真实的Dom结构中,所以对它所做的操作不会触发浏览器的回流,只会在他插入dom的时候触发一次而已。

    上面把多个动态生成的div插入到了虚拟节点里,在最后完成之后只做了一次插入,这样就只会触发一次回流。
    但是在数量太多的时候,哪怕是一次插入,也会因为浏览器渲染不过来导致失去响应,这时候就需要增加一定的时间间隔,可以使用setTimeout,也可以使用一个api------requestAnimationFrame

requestAnimationFrame()

    1.方法是为了动画 专门使用的api,在通常的动画中会定义一个定时器来几秒几秒的发生变化,但是为了性能和更加方便,它提供了这个可以在1秒钟运行大约60次(≈16.7ms)回调的api。
    而且会把这一刻所有的dom操作缓存起来,在一次回流重绘中完成操作,它的每次调用并不是指定时间的,而是跟紧浏览器的刷新频率,所以可以做到:在浏览器的刷新频率时进行回流,保证性能效率。
    当页面不是激活状态的情况下,这个函数将会停止回调,进行暂停来节省cpu操作。激活时再继续。
    在元素隐藏时不会进行重绘回流。

    2.它的返回值为一个long的标识符,和settimeout一样,可以调用cancelAnimationFrame()传入这个标识符来取消这个回调。
    使用这个可以在浏览器下一次’刷新’的时候运行指定的回调,在这里来插入这多个节点。
    使用这样可以大批量插入很多数据 页面也不会失去响应卡住,可以保证比较好的性能

原文地址:https://www.cnblogs.com/yxkNotes/p/13950122.html