81

我对大量 dom elmenets 和性能有疑问。

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

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

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

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

4

3 回答 3

103

我们不得不在FoldingText上处理类似的问题。随着文档变得越来越大,创建了更多的线元素和相关的跨度元素。浏览器引擎似乎卡住了,因此需要找到更好的解决方案。

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

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

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

var top = document.scrollTop;
var width = window.innerWidth;
var height = window.innerHeight;

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

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

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

其次,你需要一个数据结构来知道哪些元素在那个区域是可见的

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

var boundingRect = element.getBoundingClientRect()

我说的是纯 javascript,但如果您使用的是 jQuery $.offset, , 和此处$.position列出的方法会很有帮助。

同样,使用数据结构仅作为缓存很重要,但如果您愿意,您可以随时进行(尽管正如我所说的那样,这些操作很昂贵)。另外,请注意更改 css 样式和调用这些方法。这些函数会强制重绘,因此您会看到性能问题。

最后,只需将屏幕外的元素替换为单个<div>元素,例如计算高度的元素

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

  • 创建一个<div>具有 css 高度集(以像素为单位)的元素高度之和

  • 用类名标记它,这样你就知道它是一个填充 div
  • 从这个 div 覆盖的 dom 中删除所有元素
  • 而是插入这个新创建的 div

对位于可见视口之后的元素重复此操作。

查找滚动和调整大小事件。在每次滚动时,您都需要返回数据结构,删除填充 div,创建之前从屏幕上删除的元素,并相应地添加新的填充 div。

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

tl;博士

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

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

希望这可以帮助。

于 2012-09-27T03:33:13.733 回答
27

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

我看了一下 Facebook,他们似乎没有在 Firefox 上做任何特别的事情。向下滚动时,页面顶部的 DOM 元素不会改变。在 Facebook 不允许您进一步滚动之前,Firefox 的内存使用量攀升至大约 500 兆。

Twitter 似乎与 Facebook 相同。

谷歌地图是一个不同的故事 - 从 DOM 中移除视野之外的地图图块(尽管不是立即)。

于 2012-09-27T02:28:19.247 回答
10

现在是 2019 年。这个问题真的很老了,但我认为它仍然是相关且有趣的,并且可能在今天发生了一些变化,因为我们现在也都倾向于使用 React JS。

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

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

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

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

感谢您的关注!

于 2019-07-10T22:10:37.450 回答