当我们在公司做项目的时候,难免会遇到后端接口直接给你返回成千上万的数据进行渲染。如果我们直接一股脑遍历添加的话,就会导致空白页面的等待时间是很长且异常卡顿,那么对于数据过大的渲染就需要进行特殊的处理。这也是一道非常经典的面试题。下面我将介绍几种通用的方法。

分页处理

分页处理就不过多描述了,需要和后端进行搭配,接口传递page,size等参数

懒加载

懒加载的话这边需要判断目标标签的offsetTop-scrollTop<clientHeight来决定是否进行数据获取或者渲染,多用于图片懒加载。

定时处理

当我们接受到成千上万的数据要进行渲染时,可能较多的人会使用setTineout来作为定时器,通过分块的方式定时渲染。 但使用 requestAnimationFrame的效果是会比 setTimeout 的性能更好,因为使用前者的时候浏览器会帮我们进行处理优化,在最优的时候进行调用,而不是像后者设置一个时间。

另外,让我们往一个dom节点插入数据的时候,我们99%都会使用document.createELement,但是如果在该场景下,你插入一条数据都会造成DOM树的重新渲染,当插入的元素多时会造成没必要的开销。但是我们可以使用document.Fragment来使用,它就像vue里面的template后者react的<></>,不是一个真实的元素标签。

createElement相比,它最大的好处就是不会触发DOM树的重新渲染,且不会对性能造成影响。因为所有的节点会被一次性插入到文档中,所以仅会发生一个重渲染的操作,而不是每个节点分别被插入到文档中从而发生多次重渲染的操作。

<!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>Document</title>
  </head>
  <body>
    <ul id="list"></ul>
    <script>
      const total = 10000;
      const num = 20;
      const times = Math.ceil(total / num);
      let currentNums = 0;
      const ul = document.querySelector("#list");
      function add() {
        let frag = new DocumentFragment();
        for (let i = 0; i < num; i++) {
          const li = document.createElement("li");
          li.innerHTML = Math.floor(i + currentNums * num);
          frag.appendChild(li);
        }
        currentNums++;
        ul.appendChild(frag);
        if (currentNums < times) {
          window.requestAnimationFrame(add);
        }
      }
      window.requestAnimationFrame(add);
    </script>
  </body>
</html>

永远年轻,永远热泪盈眶。