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

时间:2012-09-27 02:11:24

标签: javascript performance dom

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

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

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

  1. 将display设置为none以显示隐藏项以避免重排
  2. 从dom中删除不可见的项目,然后根据需要重新添加。
  3. 它们是否有其他方法可以改善包含大量dom元素的页面?

3 个答案:

答案 0 :(得分:94)

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

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

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

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

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

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

Get the browser viewport dimensions with JavaScript

Cross-browser method for detecting the scrollTop of the browser window

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

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

var boundingRect = element.getBoundingClientRect()

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

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

最后,只需将屏幕上的元素替换为具有计算高度的单个<div>元素

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

  • 创建<div>,其中css高度设置(以像素为单位)为元素高度的总和

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

重复强于可见视口后的元素。

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

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

TL;博士

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

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

希望这有帮助。

答案 1 :(得分:24)

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

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

Twitter似乎与Facebook相同。

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

答案 2 :(得分:1)

现在是2019年。这个问题确实很老,但是我认为它仍然是相关且有趣的,并且从今天起可能有所改变,因为我们现在都倾向于使用React JS。

我注意到,Facebook的时间轴似乎使用了display: none !important隐藏的内容簇,只要它们不在视野中,因此所有先前呈现的DOM元素都保留在DOM中,只是用display: none !important隐藏那些看不见的东西。 另外,隐藏群集的整体高度设置为隐藏群集的父级div

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

enter image description here

enter image description here

enter image description here

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

感谢您的关注!