【面试-优化渲染性能】如何渲染几万条数据并不卡住界面

【面试题】
如何渲染几万条数据并不卡住界面

这道题考察了如何在不卡住页面的情况下渲染数据,也就是说不能一次性将几万条都渲染出来,而应该一次渲染部分 DOM,那么就可以通过 requestAnimationFrame 来每 16 ms 刷新一次。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <ul>控件</ul>
  <script>
    setTimeout(() => {
      
      
      // 插入十万条数据
      const total = 100000
      // 一次插入 20 条,如果觉得性能不好就减少
      const once = 20
      // 渲染数据总共需要几次
      const loopCount = total / once
      let countOfRender = 0
      let 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);
  </script>
</body>
</html>

【问题】

你会发现这个面试题还可以有更优解:

上面的方案属于是分页加触底加载,只往里面添加dom不删除之前的,页面卡顿可不止加载时候卡顿的一个问题

还有一个问题就是加载完卡顿
这还只是一个空元素,里面有点其他东西呢,加点图片看效果,页面滚动时候,加载一半就G了

总结:分段加载是能缓解加载问题,但是终究是加载了,来回滚动肯定会卡

【解决方案】

虚拟列表改成懒加载或者做成了搜索下拉,也可以使用css版虚拟列表:树结构点击的时候请求

这里利用 content-visibility: auto 实现虚拟列表

接下来是 content-visibility 的核心用法,利用 auto 属性值。

content-visibility: auto 的作用是,如果该元素不在屏幕上,并且与用户无关,则不会渲染其后代元素。是不是与 LazyLoad 非常类似?

我们来看这样一个 DEMO ,了解其作用:

假设,我们存在这样一个 HTML 结构,含有大量的文本内容:

...
// ... 包含了 N 个 paragraph
...
每个 .paragraph 的内容如下: ![在这里插入图片描述](https://img-blog.csdnimg.cn/1546f2556b71419fb4eb570b02edbbd0.jpeg#pic_center)

因此,整个的页面看起来就是这样的:

在这里插入图片描述

由于,我们没有对页面内容进行任何处理,因此,所有的 .paragraph 在页面刷新的一瞬间,都会进行渲染,看到的效果就如上所示。

当然,现代浏览器愈加趋于智能,基于这种场景,其实我们非常希望对于仍未看到,仍旧未滚动到的区域,可以延迟加载,只有到我们需要展示、滚动到该处时,页面内容才进行渲染。

基于这种场景,content-visibility: auto 就应运而生了,它允许浏览器对于设置了该属性的元素进行判断,如果该元素当前不处于视口内,则不渲染该元素。

我们基于上述的代码,只需要最小化,添加这样一段代码:

.paragraph {
    content-visibility: auto;
}

再看看效果,仔细观察右侧的滚动条:
在这里插入图片描述

这里我使用了 ::-webkit-scrollbar 相关样式,让滚动条更明显。
可能你还没意识到发生了什么,我们对比下添加了 content-visibility: auto 和没有添加 content-visibility: auto 的两种效果下文本的整体高度:
在这里插入图片描述

有着非常明显的差异,这是因为,设置了 content-visibility: auto 的元素,在非可视区域内,目前并没有被渲染,因此,右侧内容的高度其实是比正常状态下少了一大截的。

实际开始进行滚动,会发生滚动条变小

由于下方的元素在滚动的过程中,出现在视口范围内才被渲染,因此,滚动条出现了明显的飘忽不定的抖动现象。(当然这也是使用了 content-visibility: auto 的一个小问题之一),不过明显可以看出,这与我们通常使用 JavaScript 实现的虚拟列表非常类似。

当然,在向下滚动的过程中,上方消失的已经被渲染过且消失在视口的元素,也会因为消失在视口中,重新被隐藏。因此,即便页面滚动到最下方,整体的滚动条高度还是没有什么变化的。

content-visibility 是否能够优化渲染性能?.

相关参考:https://zhuanlan.zhihu.com/p/528538686

猜你喜欢

转载自blog.csdn.net/weixin_44070058/article/details/128914651