无限滚动或大量dom元素的表现?

Moo*_*oon 67 javascript performance dom

我对大量的dom elmenets和表现有疑问.

假设我在页面上有6000个dom元素,并且当用户与页面交互(用户滚动以创建新的dom元素)(如twitter)时,元素的数量可以增加.

为了提高页面的性能,我只能想到两件事.

  1. 将display设置为none以显示隐形项以避免重排
  2. 从dom中删除不可见的项目,然后根据需要重新添加它们.

它们是否有其他方法可以改善具有大量dom元素的页面?

Mut*_*hir 95

我们不得不在FoldingText上处理类似的问题.随着文档变大,创建了更多的线元素和相关的span元素.浏览器引擎似乎只是窒息,因此需要找到更好的解决方案.

以下是我们所做的,可能会或可能不会对您的目的有用:

将整个页面可视化为长文档,将浏览器视口视为长文档特定部分的镜头.你真的只需要在镜头内显示部分.

所以第一部分是计算可见视口.(这取决于元素的放置方式,绝对/固定/默认)

var top = document.scrollTop;
var width = window.innerWidth;
var height = window.innerHeight;
Run Code Online (Sandbox Code Playgroud)

更多资源可用于查找基于跨浏览器的视口:

使用JavaScript获取浏览器视口尺寸

用于检测浏览器窗口的scrollTop的跨浏览器方法

其次,您需要一个数据结构来了解哪个元素在该区域中可见

我们已经有一个平衡的二叉搜索树用于文本编辑,所以我们将它扩展到管理行高度,所以这部分对我们来说相对容易.我认为您不需要复杂的数据结构来管理元素高度; 一个简单的数组或对象可能会很好.只需确保您可以轻松查询高度和尺寸.现在,您将如何获得所有元素的高度数据.非常简单(但对于大量元素来说计算成本很高!)

var boundingRect = element.getBoundingClientRect()
Run Code Online (Sandbox Code Playgroud)

我说的是纯粹的javascript,但是如果你使用的是jQuery $.offset,那么这里$.position列出的方法会非常有用.

同样,使用数据结构仅作为缓存很重要,但如果您愿意,您可以动态执行(尽管我已经说过这些操作很昂贵).另外,请注意更改css样式并调用这些方法.这些函数强制重绘,因此您将看到性能问题.

最后,只需用一个<div>具有计算高度的单个元素替换屏幕外的元素

  • 现在,您拥有存储在数据结构中的所有元素的高度,查询位于可见视口之前的所有元素.

  • 创建一个<div>css高度设置(以像素为单位)到元素高度的总和

  • 用类名标记它,以便您知道它的填充div
  • 从该div覆盖的dom中删除所有元素
  • 插入这个新创建的div代替

对可见视口后面的元素重复此操作.

查找滚动和调整事件大小.在每个滚动条上,您将需要返回到数据结构,删除填充div,创建先前从屏幕中删除的元素,并相应地添加新的填充div.

:)这是一个漫长而复杂的方法,但对于大型文档,它大大提高了我们的性能.

TL;博士

我不确定我是否正确解释了它,但这种方法的要点是:

  • 了解元素的垂直尺寸
  • 知道滚动的视图端口
  • 使用单个div表示所有屏幕外元素(高度等于其覆盖的所有元素高度的总和)
  • 在任何给定时间总共需要两个div,一个用于可见视口上方的元素,一个用于下面的元素.
  • 通过侦听滚动和调整大小事件来跟踪视图端口.相应地重新创建div和可见元素

希望这可以帮助.

  • @Moon:这个答案中概述的相同技术已经以插件的形式实现.[ClusterizeJS](http://nexts.github.io/Clusterize.js/).完全按预期工作,如果需要,它还支持项目奇偶校验.它真的很棒!(仅供参考:我不是它的开发者) (7认同)
  • 顺便说一句,我发现这是处理大量DOM元素的唯一方法,仍然有合理的滚动体验.此外,在(jquery)滚动处理程序中获取scrollTop不会导致重绘.实际上它永远不会,它只清除重绘和重绘的队列,以便可以返回最新的scrollTop.我的猜测是,在处理scrollevent的那一刻它已经是最新的. (3认同)

cbp*_*cbp 24

没有经验,但这里有一些很棒的提示:http://engineering.linkedin.com/linkedin-ipad-5-techniques-smooth-infinite-scrolling-html5

我看过Facebook,他们似乎没有对Firefox做任何特别的事情.向下滚动时,页面顶部的DOM元素不会更改.在Facebook不允许您进一步滚动之前,Firefox的内存使用率攀升至约500微秒.

Twitter似乎与Facebook相同.

谷歌地图是一个不同的故事 - 视图中的地图图块从DOM中删除(尽管不是立即).

  • 看看Pinterest是如何做到这一点真的很有趣.当你向下和向后滚动时,他们似乎已经弄明白了,因为他们动态加载元素.在任何给定时间,它们似乎总是在Feed页面上加载了一定数量的Pins. (2认同)

ton*_*nix 10

现在是 2019 年。这个问题真的很老了,但我认为它仍然是相关和有趣的,也许今天有所改变,因为我们现在也倾向于使用 React JS。

我注意到 Facebook 的时间线似乎使用了内容集群,display: none !important一旦集群消失,这些内容就会被隐藏起来,所以 DOM 之前呈现的所有元素都保留在 DOM 中,只是那些不在视野中的元素被隐藏起来display: none !important. 此外,隐藏簇的整体高度设置为隐藏簇的父级div

以下是我制作的一些屏幕截图:

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明

截至 2019 年,您如何看待这种方法?另外,对于那些使用 React 的人,它如何在 React 中实现?收到您对这个棘手话题的意见和想法会很棒。

感谢您的关注!

  • 有一个名为react-window的库,它与上面的解释非常接近 (2认同)